diff options
1598 files changed, 30568 insertions, 9762 deletions
diff --git a/Android.bp b/Android.bp index 808879f8839a..3046b20c7096 100644 --- a/Android.bp +++ b/Android.bp @@ -53,6 +53,7 @@ filegroup { "core/java/android/view/DisplayAdjustments.java", ], path: "core/java", + visibility: ["//frameworks/base/test-mock"], } filegroup { @@ -73,6 +74,14 @@ filegroup { } filegroup { + name: "framework-identity-sources", + srcs: [ + "identity/java/**/*.java", + ], + path: "identity/java", +} + +filegroup { name: "framework-keystore-sources", srcs: [ "keystore/java/**/*.java", @@ -216,6 +225,7 @@ filegroup { ":framework-drm-sources", ":framework-graphics-sources", ":framework-keystore-sources", + ":framework-identity-sources", ":framework-location-sources", ":framework-lowpan-sources", ":framework-media-sources", @@ -232,11 +242,13 @@ filegroup { ":framework-wifi-sources", ":PacProcessor-aidl-sources", ":ProxyHandler-aidl-sources", + ":net-utils-framework-common-srcs", // AIDL from frameworks/base/native/ ":platform-compat-native-aidl", // AIDL sources from external directories + ":credstore_aidl", ":dumpstate_aidl", ":framework_native_aidl", ":gatekeeper_aidl", @@ -265,9 +277,10 @@ filegroup { filegroup { name: "framework-updatable-sources", srcs: [ - ":framework-sdkext-sources", + ":framework-sdkextensions-sources", ":framework-tethering-srcs", ":updatable-media-srcs", + ":ike-srcs", ] } @@ -287,6 +300,7 @@ java_defaults { "core/java", "drm/java", "graphics/java", + "identity/java", "keystore/java", "location/java", "lowpan/java", @@ -430,6 +444,7 @@ java_library { name: "framework-minus-apex", defaults: ["framework-defaults"], srcs: [":framework-non-updatable-sources"], + libs: ["ike-stubs"], installable: true, javac_shard_size: 150, required: [ @@ -463,8 +478,10 @@ java_library { static_libs: [ "framework-minus-apex", "updatable_media_stubs", - "framework-sdkext-stubs-systemapi", - // TODO(jiyong): add more stubs for APEXes here + "framework-sdkextensions-stubs-systemapi", + // TODO(b/147200698): should be the stub of framework-tethering + "framework-tethering", + "ike-stubs", ], sdk_version: "core_platform", apex_available: ["//apex_available:platform"], @@ -587,6 +604,19 @@ java_library { } filegroup { + name: "framework-ike-shared-srcs", + visibility: ["//frameworks/opt/net/ike"], + srcs: [ + "core/java/android/annotation/StringDef.java", + "core/java/android/net/annotations/PolicyDirection.java", + "core/java/com/android/internal/util/IState.java", + "core/java/com/android/internal/util/State.java", + "core/java/com/android/internal/util/StateMachine.java", + "telephony/java/android/telephony/Annotation.java", + ], +} + +filegroup { name: "framework-networkstack-shared-srcs", srcs: [ // TODO: remove these annotations as soon as we can use andoid.support.annotations.* @@ -603,6 +633,7 @@ filegroup { "core/java/com/android/internal/util/StateMachine.java", "core/java/com/android/internal/util/TrafficStatsConstants.java", "core/java/com/android/internal/util/WakeupMessage.java", + "core/java/com/android/internal/util/TokenBucket.java", "core/java/android/net/shared/*.java", ], } @@ -612,13 +643,14 @@ filegroup { name: "framework-tethering-shared-srcs", srcs: [ "core/java/android/util/LocalLog.java", - "core/java/com/android/internal/util/BitUtils.java", "core/java/com/android/internal/util/IndentingPrintWriter.java", "core/java/com/android/internal/util/IState.java", "core/java/com/android/internal/util/MessageUtils.java", "core/java/com/android/internal/util/Preconditions.java", "core/java/com/android/internal/util/State.java", "core/java/com/android/internal/util/StateMachine.java", + "core/java/com/android/internal/util/TrafficStatsConstants.java", + "core/java/android/net/shared/Inet4AddressUtils.java", ], } @@ -905,6 +937,7 @@ java_library { "core/java/android/os/RemoteException.java", "core/java/android/util/AndroidException.java", ], + libs: [ "unsupportedappusage" ], dxflags: ["--core-library"], installable: false, @@ -1005,6 +1038,7 @@ filegroup { "core/java/android/util/TimeUtils.java", "core/java/com/android/internal/os/SomeArgs.java", "core/java/com/android/internal/util/AsyncChannel.java", + "core/java/com/android/internal/util/AsyncService.java", "core/java/com/android/internal/util/BitwiseInputStream.java", "core/java/com/android/internal/util/FastXmlSerializer.java", "core/java/com/android/internal/util/HexDump.java", diff --git a/ApiDocs.bp b/ApiDocs.bp index e373db66925f..c40004cf8e5c 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -121,8 +121,10 @@ framework_docs_only_args = " -android -manifest $(location core/res/AndroidManif doc_defaults { name: "framework-docs-default", - libs: framework_docs_only_libs + - ["stub-annotations"], + libs: framework_docs_only_libs + [ + "stub-annotations", + "unsupportedappusage", + ], html_dirs: [ "docs/html", ], diff --git a/StubLibraries.bp b/StubLibraries.bp index 78f1b9ca26e5..baa3c615039d 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -41,10 +41,9 @@ packages_to_document = [ ] stubs_defaults { - name: "metalava-api-stubs-default", + name: "metalava-non-updatable-api-stubs-default", srcs: [ ":framework-non-updatable-sources", - ":framework-updatable-sources", "core/java/**/*.logtags", ":opt-telephony-srcs", ":opt-net-voip-srcs", @@ -64,14 +63,23 @@ stubs_defaults { "sdk-dir", "api-versions-jars-dir", ], - sdk_version: "core_platform", filter_packages: packages_to_document, } +stubs_defaults { + name: "metalava-api-stubs-default", + defaults: ["metalava-non-updatable-api-stubs-default"], + srcs: [":framework-updatable-sources"], + sdk_version: "core_platform", +} + ///////////////////////////////////////////////////////////////////// // *-api-stubs-docs modules providing source files for the stub libraries ///////////////////////////////////////////////////////////////////// +// api-stubs-docs, system-api-stubs-docs, and test-api-stubs-docs have APIs +// from the non-updatable part of the platform as well as from the updatable +// modules droidstubs { name: "api-stubs-docs", defaults: ["metalava-api-stubs-default"], @@ -112,7 +120,10 @@ droidstubs { arg_files: [ "core/res/AndroidManifest.xml", ], - args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\)", + args: metalava_framework_docs_args + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\)", check_api: { current: { api_file: "api/system-current.txt", @@ -155,6 +166,111 @@ droidstubs { } ///////////////////////////////////////////////////////////////////// +// Following droidstubs modules are for extra APIs for modules. +// The framework currently have two more API surfaces for modules: +// @SystemApi(client=MODULE_APPS) and @SystemApi(client=MODULE_LIBRARIES) +///////////////////////////////////////////////////////////////////// + +// TODO(b/146727827) remove the *-api modules when we can teach metalava +// about the relationship among the API surfaces. Currently, these modules are only to generate +// the API signature files and ensure that the APIs evolve in a backwards compatible manner. +// They however are NOT used for building the API stub. +droidstubs { + name: "module-app-api", + defaults: ["metalava-non-updatable-api-stubs-default"], + libs: ["framework-all"], + arg_files: ["core/res/AndroidManifest.xml"], + args: metalava_framework_docs_args + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\)", + check_api: { + current: { + api_file: "api/module-app-current.txt", + removed_api_file: "api/module-app-removed.txt", + }, + // TODO(b/147559833) enable the compatibility check against the last release API + // and the API lint + //last_released: { + // api_file: ":last-released-module-app-api", + // removed_api_file: "api/module-app-removed.txt", + // baseline_file: ":module-app-api-incompatibilities-with-last-released" + //}, + //api_lint: { + // enabled: true, + // new_since: ":last-released-module-app-api", + // baseline_file: "api/module-app-lint-baseline.txt", + //}, + }, + //jdiff_enabled: true, +} + +droidstubs { + name: "module-lib-api", + defaults: ["metalava-non-updatable-api-stubs-default"], + libs: ["framework-all"], + arg_files: ["core/res/AndroidManifest.xml"], + args: metalava_framework_docs_args + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," + + "process=android.annotation.SystemApi.Process.ALL\\)", + check_api: { + current: { + api_file: "api/module-lib-current.txt", + removed_api_file: "api/module-lib-removed.txt", + }, + // TODO(b/147559833) enable the compatibility check against the last release API + // and the API lint + //last_released: { + // api_file: ":last-released-module-lib-api", + // removed_api_file: "api/module-lib-removed.txt", + // baseline_file: ":module-lib-api-incompatibilities-with-last-released" + //}, + //api_lint: { + // enabled: true, + // new_since: ":last-released-module-lib-api", + // baseline_file: "api/module-lib-lint-baseline.txt", + //}, + }, + //jdiff_enabled: true, +} + +// The following two droidstubs modules generate source files for the API stub libraries for +// modules. Note that they not only include their own APIs but also other APIs that have +// narrower scope. For example, module-lib-api-stubs-docs includes all @SystemApis not just +// the ones with 'client=MODULE_LIBRARIES'. +droidstubs { + name: "module-app-api-stubs-docs", + defaults: ["metalava-non-updatable-api-stubs-default"], + libs: ["framework-all"], + arg_files: ["core/res/AndroidManifest.xml"], + args: metalava_framework_docs_args + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\)" + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\)", +} + +droidstubs { + name: "module-lib-api-stubs-docs", + defaults: ["metalava-non-updatable-api-stubs-default"], + libs: ["framework-all"], + arg_files: ["core/res/AndroidManifest.xml"], + args: metalava_framework_docs_args + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\)" + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\)" + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," + + "process=android.annotation.SystemApi.Process.ALL\\)", +} + +///////////////////////////////////////////////////////////////////// // android_*_stubs_current modules are the stubs libraries compiled // from *-api-stubs-docs ///////////////////////////////////////////////////////////////////// @@ -169,7 +285,6 @@ java_defaults { java_resources: [ ":notices-for-framework-stubs", ], - sdk_version: "core_current", system_modules: "none", java_version: "1.8", compile_dex: true, @@ -187,6 +302,7 @@ java_library_static { "private-stub-annotations-jar", ], defaults: ["framework-stubs-default"], + sdk_version: "core_current", } java_library_static { @@ -201,6 +317,7 @@ java_library_static { "private-stub-annotations-jar", ], defaults: ["framework-stubs-default"], + sdk_version: "core_current", } java_library_static { @@ -215,21 +332,37 @@ java_library_static { "private-stub-annotations-jar", ], defaults: ["framework-stubs-default"], + sdk_version: "core_current", } -java_system_modules { - name: "android_stubs_current_system_modules", - libs: ["android_stubs_current"], -} - -java_system_modules { - name: "android_system_stubs_current_system_modules", - libs: ["android_system_stubs_current"], +java_library_static { + name: "framework_module_app_stubs_current", + srcs: [ + ":module-app-api-stubs-docs", + ], + libs: [ + "stub-annotations", + "framework-all", + ], + static_libs: [ + "private-stub-annotations-jar", + ], + defaults: ["framework-stubs-default"], } -java_system_modules { - name: "android_test_stubs_current_system_modules", - libs: ["android_test_stubs_current"], +java_library_static { + name: "framework_module_lib_stubs_current", + srcs: [ + ":module-lib-api-stubs-docs", + ], + libs: [ + "stub-annotations", + "framework-all", + ], + static_libs: [ + "private-stub-annotations-jar", + ], + defaults: ["framework-stubs-default"], } ///////////////////////////////////////////////////////////////////// diff --git a/apex/Android.bp b/apex/Android.bp index 9ea395374e3a..c3b001471a12 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -34,6 +34,36 @@ stubs_defaults { stubs_defaults { name: "framework-module-stubs-defaults-systemapi", - args: mainline_stubs_args + " --show-annotation android.annotation.SystemApi ", + args: mainline_stubs_args + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\) ", + installable: false, +} + +stubs_defaults { + name: "framework-module-stubs-defaults-module_apps_api", + args: mainline_stubs_args + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\) " + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\) ", + installable: false, +} + +stubs_defaults { + name: "framework-module-stubs-defaults-module_libs_api", + args: mainline_stubs_args + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\) " + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_APPS," + + "process=android.annotation.SystemApi.Process.ALL\\) " + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," + + "process=android.annotation.SystemApi.Process.ALL\\) ", installable: false, } diff --git a/apex/sdkext/TEST_MAPPING b/apex/sdkext/TEST_MAPPING deleted file mode 100644 index 91947f39980a..000000000000 --- a/apex/sdkext/TEST_MAPPING +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presubmit": [ - { - "name": "CtsSdkExtTestCases" - } - ] -} diff --git a/apex/sdkext/Android.bp b/apex/sdkextensions/Android.bp index f62f167cdcfa..4c5c2b2cfd4f 100644 --- a/apex/sdkext/Android.bp +++ b/apex/sdkextensions/Android.bp @@ -18,21 +18,26 @@ package { apex { name: "com.android.sdkext", - manifest: "manifest.json", + defaults: [ "com.android.sdkext-defaults" ], binaries: [ "derive_sdk" ], - java_libs: [ "framework-sdkext" ], + prebuilts: [ "cur_sdkinfo" ], + manifest: "manifest.json", +} + +apex_defaults { + name: "com.android.sdkext-defaults", + java_libs: [ "framework-sdkextensions" ], prebuilts: [ - "com.android.sdkext.ldconfig", - "cur_sdkinfo", - "derive_sdk.rc", + "com.android.sdkext.ldconfig", + "derive_sdk.rc", ], key: "com.android.sdkext.key", certificate: ":com.android.sdkext.certificate", } sdk { - name: "sdkext-sdk", - java_header_libs: [ "framework-sdkext-stubs-systemapi" ], + name: "sdkextensions-sdk", + java_header_libs: [ "framework-sdkextensions-stubs-systemapi" ], } apex_key { diff --git a/apex/sdkext/OWNERS b/apex/sdkextensions/OWNERS index feb274262bef..feb274262bef 100644 --- a/apex/sdkext/OWNERS +++ b/apex/sdkextensions/OWNERS diff --git a/apex/sdkextensions/TEST_MAPPING b/apex/sdkextensions/TEST_MAPPING new file mode 100644 index 000000000000..4e1883382e2c --- /dev/null +++ b/apex/sdkextensions/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "CtsSdkExtensionsTestCases" + }, + { + "name": "apiextensions_e2e_tests" + } + ] +} diff --git a/apex/sdkext/com.android.sdkext.avbpubkey b/apex/sdkextensions/com.android.sdkext.avbpubkey Binary files differindex 8f47741ed3b8..8f47741ed3b8 100644 --- a/apex/sdkext/com.android.sdkext.avbpubkey +++ b/apex/sdkextensions/com.android.sdkext.avbpubkey diff --git a/apex/sdkext/com.android.sdkext.pem b/apex/sdkextensions/com.android.sdkext.pem index 816460183aa3..816460183aa3 100644 --- a/apex/sdkext/com.android.sdkext.pem +++ b/apex/sdkextensions/com.android.sdkext.pem diff --git a/apex/sdkext/com.android.sdkext.pk8 b/apex/sdkextensions/com.android.sdkext.pk8 Binary files differindex ccc0bf438cd1..ccc0bf438cd1 100644 --- a/apex/sdkext/com.android.sdkext.pk8 +++ b/apex/sdkextensions/com.android.sdkext.pk8 diff --git a/apex/sdkext/com.android.sdkext.x509.pem b/apex/sdkextensions/com.android.sdkext.x509.pem index 45d2ade354d4..45d2ade354d4 100644 --- a/apex/sdkext/com.android.sdkext.x509.pem +++ b/apex/sdkextensions/com.android.sdkext.x509.pem diff --git a/apex/sdkext/derive_sdk/Android.bp b/apex/sdkextensions/derive_sdk/Android.bp index c4e3c296f210..cf49902d9978 100644 --- a/apex/sdkext/derive_sdk/Android.bp +++ b/apex/sdkextensions/derive_sdk/Android.bp @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_binary { - name: "derive_sdk", +cc_defaults { + name: "derive_sdk-defaults", srcs: [ "derive_sdk.cpp", "sdk.proto", @@ -30,6 +30,24 @@ cc_binary { ], } +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" ] +} + prebuilt_etc { name: "derive_sdk.rc", src: "derive_sdk.rc", diff --git a/apex/sdkext/derive_sdk/derive_sdk.cpp b/apex/sdkextensions/derive_sdk/derive_sdk.cpp index 0a9711677015..6fb7ef43416e 100644 --- a/apex/sdkext/derive_sdk/derive_sdk.cpp +++ b/apex/sdkextensions/derive_sdk/derive_sdk.cpp @@ -26,7 +26,7 @@ #include <android-base/logging.h> #include <android-base/properties.h> -#include "frameworks/base/apex/sdkext/derive_sdk/sdk.pb.h" +#include "frameworks/base/apex/sdkextensions/derive_sdk/sdk.pb.h" using com::android::sdkext::proto::SdkVersion; diff --git a/apex/sdkext/derive_sdk/derive_sdk.rc b/apex/sdkextensions/derive_sdk/derive_sdk.rc index 1b667949eeaa..1b667949eeaa 100644 --- a/apex/sdkext/derive_sdk/derive_sdk.rc +++ b/apex/sdkextensions/derive_sdk/derive_sdk.rc diff --git a/apex/sdkext/derive_sdk/sdk.proto b/apex/sdkextensions/derive_sdk/sdk.proto index d15b93552ff4..d15b93552ff4 100644 --- a/apex/sdkext/derive_sdk/sdk.proto +++ b/apex/sdkextensions/derive_sdk/sdk.proto diff --git a/apex/sdkext/framework/Android.bp b/apex/sdkextensions/framework/Android.bp index a50dc3d4f349..dd174734df6d 100644 --- a/apex/sdkext/framework/Android.bp +++ b/apex/sdkextensions/framework/Android.bp @@ -17,55 +17,63 @@ package { } filegroup { - name: "framework-sdkext-sources", + name: "framework-sdkextensions-sources", srcs: [ "java/**/*.java", ], path: "java", - visibility: [ "//frameworks/base:__pkg__" ] // For the "global" stubs. + visibility: [ "//frameworks/base" ] // For the "global" stubs. } java_library { - name: "framework-sdkext", - srcs: [ ":framework-sdkext-sources" ], + name: "framework-sdkextensions", + srcs: [ ":framework-sdkextensions-sources" ], sdk_version: "system_current", libs: [ "framework-annotations-lib" ], permitted_packages: [ "android.os.ext" ], installable: true, - visibility: [ "//frameworks/base/apex/sdkext:__pkg__" ], + visibility: [ + "//frameworks/base/apex/sdkextensions", + "//frameworks/base/apex/sdkextensions/testing", + ], + hostdex: true, // for hiddenapi check + apex_available: [ + "com.android.sdkext", + "test_com.android.sdkext", + ], } droidstubs { - name: "framework-sdkext-droidstubs-publicapi", + name: "framework-sdkextensions-droidstubs-publicapi", defaults: [ - "framework-sdkext-stubs-defaults", + "framework-sdkextensions-stubs-defaults", "framework-module-stubs-defaults-publicapi", ] } droidstubs { - name: "framework-sdkext-droidstubs-systemapi", + name: "framework-sdkextensions-droidstubs-systemapi", defaults: [ - "framework-sdkext-stubs-defaults", + "framework-sdkextensions-stubs-defaults", "framework-module-stubs-defaults-systemapi", ] } stubs_defaults { - name: "framework-sdkext-stubs-defaults", + name: "framework-sdkextensions-stubs-defaults", srcs: [ - ":framework-sdkext-sources", + ":framework-sdkextensions-sources", ":framework-annotations", ], sdk_version: "system_current", } java_library { - name: "framework-sdkext-stubs-systemapi", - srcs: [":framework-sdkext-droidstubs-systemapi"], + name: "framework-sdkextensions-stubs-systemapi", + srcs: [":framework-sdkextensions-droidstubs-systemapi"], sdk_version: "system_current", visibility: [ - "//frameworks/base:__pkg__", // Framework - "//frameworks/base/apex/sdkext:__pkg__", // sdkext SDK + "//frameworks/base", // Framework + "//frameworks/base/apex/sdkextensions", // sdkextensions SDK ] } diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java index a8a7effa9b6c..a8a7effa9b6c 100644 --- a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java +++ b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java diff --git a/apex/sdkext/framework/java/android/os/ext/package.html b/apex/sdkextensions/framework/java/android/os/ext/package.html index 34c1697c01fd..34c1697c01fd 100644 --- a/apex/sdkext/framework/java/android/os/ext/package.html +++ b/apex/sdkextensions/framework/java/android/os/ext/package.html diff --git a/apex/sdkext/gen_sdkinfo.py b/apex/sdkextensions/gen_sdkinfo.py index 5af478ba7fe6..5af478ba7fe6 100644 --- a/apex/sdkext/gen_sdkinfo.py +++ b/apex/sdkextensions/gen_sdkinfo.py diff --git a/apex/sdkext/ld.config.txt b/apex/sdkextensions/ld.config.txt index b4470685f4fc..dcc69b892760 100644 --- a/apex/sdkext/ld.config.txt +++ b/apex/sdkextensions/ld.config.txt @@ -1,10 +1,10 @@ # Copyright (C) 2019 The Android Open Source Project # -# Bionic loader config file for the sdkext apex. +# Bionic loader config file for the sdkextensions apex. -dir.sdkext = /apex/com.android.sdkext/bin/ +dir.sdkextensions = /apex/com.android.sdkext/bin/ -[sdkext] +[sdkextensions] additional.namespaces = platform namespace.default.isolated = true diff --git a/apex/sdkext/manifest.json b/apex/sdkextensions/manifest.json index 048f5c4f177b..048f5c4f177b 100644 --- a/apex/sdkext/manifest.json +++ b/apex/sdkextensions/manifest.json diff --git a/apex/sdkext/sdk.proto b/apex/sdkextensions/sdk.proto index d15b93552ff4..d15b93552ff4 100644 --- a/apex/sdkext/sdk.proto +++ b/apex/sdkextensions/sdk.proto diff --git a/apex/sdkextensions/testing/Android.bp b/apex/sdkextensions/testing/Android.bp new file mode 100644 index 000000000000..e6451cc29bc2 --- /dev/null +++ b/apex/sdkextensions/testing/Android.bp @@ -0,0 +1,46 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +apex { + 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 new file mode 100644 index 000000000000..1b4a2b0c6e60 --- /dev/null +++ b/apex/sdkextensions/testing/test_manifest.json @@ -0,0 +1,4 @@ +{ + "name": "com.android.sdkext", + "version": 2147483647 +} diff --git a/api/current.txt b/api/current.txt index 7ae64b4eee1e..bba65864ad78 100644 --- a/api/current.txt +++ b/api/current.txt @@ -112,6 +112,7 @@ package android { field public static final String READ_LOGS = "android.permission.READ_LOGS"; field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS"; field public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE"; + field public static final String READ_PRECISE_PHONE_STATE = "android.permission.READ_PRECISE_PHONE_STATE"; field public static final String READ_SMS = "android.permission.READ_SMS"; field public static final String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS"; field public static final String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS"; @@ -16636,7 +16637,9 @@ package android.hardware.biometrics { ctor public BiometricPrompt.CryptoObject(@NonNull java.security.Signature); ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Cipher); ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Mac); + ctor public BiometricPrompt.CryptoObject(@NonNull android.security.identity.IdentityCredential); method public javax.crypto.Cipher getCipher(); + method @Nullable public android.security.identity.IdentityCredential getIdentityCredential(); method public javax.crypto.Mac getMac(); method public java.security.Signature getSignature(); } @@ -17574,7 +17577,9 @@ package android.hardware.fingerprint { ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature); ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher); ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac); + ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull android.security.identity.IdentityCredential); method @Deprecated public javax.crypto.Cipher getCipher(); + method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential(); method @Deprecated public javax.crypto.Mac getMac(); method @Deprecated public java.security.Signature getSignature(); } @@ -17963,6 +17968,7 @@ package android.icu.lang { field public static final int RIGHT = 7; // 0x7 field public static final int TOP = 8; // 0x8 field public static final int TOP_AND_BOTTOM = 9; // 0x9 + field public static final int TOP_AND_BOTTOM_AND_LEFT = 15; // 0xf field public static final int TOP_AND_BOTTOM_AND_RIGHT = 10; // 0xa field public static final int TOP_AND_LEFT = 11; // 0xb field public static final int TOP_AND_LEFT_AND_RIGHT = 12; // 0xc @@ -18285,6 +18291,8 @@ package android.icu.lang { field public static final int CHEROKEE_SUPPLEMENT_ID = 255; // 0xff field public static final android.icu.lang.UCharacter.UnicodeBlock CHESS_SYMBOLS; field public static final int CHESS_SYMBOLS_ID = 281; // 0x119 + field public static final android.icu.lang.UCharacter.UnicodeBlock CHORASMIAN; + field public static final int CHORASMIAN_ID = 301; // 0x12d field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_COMPATIBILITY; field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_COMPATIBILITY_FORMS; field public static final int CJK_COMPATIBILITY_FORMS_ID = 83; // 0x53 @@ -18312,6 +18320,8 @@ package android.icu.lang { field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E_ID = 256; // 0x100 field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F; field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F_ID = 274; // 0x112 + field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G; + field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G_ID = 302; // 0x12e field public static final int CJK_UNIFIED_IDEOGRAPHS_ID = 71; // 0x47 field public static final android.icu.lang.UCharacter.UnicodeBlock COMBINING_DIACRITICAL_MARKS; field public static final android.icu.lang.UCharacter.UnicodeBlock COMBINING_DIACRITICAL_MARKS_EXTENDED; @@ -18361,6 +18371,8 @@ package android.icu.lang { field public static final int DEVANAGARI_ID = 15; // 0xf field public static final android.icu.lang.UCharacter.UnicodeBlock DINGBATS; field public static final int DINGBATS_ID = 56; // 0x38 + field public static final android.icu.lang.UCharacter.UnicodeBlock DIVES_AKURU; + field public static final int DIVES_AKURU_ID = 303; // 0x12f field public static final android.icu.lang.UCharacter.UnicodeBlock DOGRA; field public static final int DOGRA_ID = 282; // 0x11a field public static final android.icu.lang.UCharacter.UnicodeBlock DOMINO_TILES; @@ -18489,6 +18501,8 @@ package android.icu.lang { field public static final int KAYAH_LI_ID = 162; // 0xa2 field public static final android.icu.lang.UCharacter.UnicodeBlock KHAROSHTHI; field public static final int KHAROSHTHI_ID = 137; // 0x89 + field public static final android.icu.lang.UCharacter.UnicodeBlock KHITAN_SMALL_SCRIPT; + field public static final int KHITAN_SMALL_SCRIPT_ID = 304; // 0x130 field public static final android.icu.lang.UCharacter.UnicodeBlock KHMER; field public static final int KHMER_ID = 36; // 0x24 field public static final android.icu.lang.UCharacter.UnicodeBlock KHMER_SYMBOLS; @@ -18527,6 +18541,8 @@ package android.icu.lang { field public static final int LINEAR_B_SYLLABARY_ID = 117; // 0x75 field public static final android.icu.lang.UCharacter.UnicodeBlock LISU; field public static final int LISU_ID = 176; // 0xb0 + field public static final android.icu.lang.UCharacter.UnicodeBlock LISU_SUPPLEMENT; + field public static final int LISU_SUPPLEMENT_ID = 305; // 0x131 field public static final android.icu.lang.UCharacter.UnicodeBlock LOW_SURROGATES; field public static final int LOW_SURROGATES_ID = 77; // 0x4d field public static final android.icu.lang.UCharacter.UnicodeBlock LYCIAN; @@ -18738,6 +18754,8 @@ package android.icu.lang { field public static final int SYLOTI_NAGRI_ID = 143; // 0x8f field public static final android.icu.lang.UCharacter.UnicodeBlock SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A; field public static final int SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A_ID = 298; // 0x12a + field public static final android.icu.lang.UCharacter.UnicodeBlock SYMBOLS_FOR_LEGACY_COMPUTING; + field public static final int SYMBOLS_FOR_LEGACY_COMPUTING_ID = 306; // 0x132 field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC; field public static final int SYRIAC_ID = 13; // 0xd field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC_SUPPLEMENT; @@ -18766,6 +18784,8 @@ package android.icu.lang { field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_COMPONENTS; field public static final int TANGUT_COMPONENTS_ID = 273; // 0x111 field public static final int TANGUT_ID = 272; // 0x110 + field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_SUPPLEMENT; + field public static final int TANGUT_SUPPLEMENT_ID = 307; // 0x133 field public static final android.icu.lang.UCharacter.UnicodeBlock TELUGU; field public static final int TELUGU_ID = 21; // 0x15 field public static final android.icu.lang.UCharacter.UnicodeBlock THAANA; @@ -18800,6 +18820,8 @@ package android.icu.lang { field public static final int WANCHO_ID = 300; // 0x12c field public static final android.icu.lang.UCharacter.UnicodeBlock WARANG_CITI; field public static final int WARANG_CITI_ID = 252; // 0xfc + field public static final android.icu.lang.UCharacter.UnicodeBlock YEZIDI; + field public static final int YEZIDI_ID = 308; // 0x134 field public static final android.icu.lang.UCharacter.UnicodeBlock YIJING_HEXAGRAM_SYMBOLS; field public static final int YIJING_HEXAGRAM_SYMBOLS_ID = 116; // 0x74 field public static final android.icu.lang.UCharacter.UnicodeBlock YI_RADICALS; @@ -19096,6 +19118,7 @@ package android.icu.lang { field public static final int CHAKMA = 118; // 0x76 field public static final int CHAM = 66; // 0x42 field public static final int CHEROKEE = 6; // 0x6 + field public static final int CHORASMIAN = 189; // 0xbd field public static final int CIRTH = 67; // 0x43 field public static final int COMMON = 0; // 0x0 field public static final int COPTIC = 7; // 0x7 @@ -19105,6 +19128,7 @@ package android.icu.lang { field public static final int DEMOTIC_EGYPTIAN = 69; // 0x45 field public static final int DESERET = 9; // 0x9 field public static final int DEVANAGARI = 10; // 0xa + field public static final int DIVES_AKURU = 190; // 0xbe field public static final int DOGRA = 178; // 0xb2 field public static final int DUPLOYAN = 135; // 0x87 field public static final int EASTERN_SYRIAC = 97; // 0x61 @@ -19146,6 +19170,7 @@ package android.icu.lang { field public static final int KATAKANA_OR_HIRAGANA = 54; // 0x36 field public static final int KAYAH_LI = 79; // 0x4f field public static final int KHAROSHTHI = 57; // 0x39 + field public static final int KHITAN_SMALL_SCRIPT = 191; // 0xbf field public static final int KHMER = 23; // 0x17 field public static final int KHOJKI = 157; // 0x9d field public static final int KHUDAWADI = 145; // 0x91 @@ -19263,6 +19288,7 @@ package android.icu.lang { field public static final int WARANG_CITI = 146; // 0x92 field public static final int WESTERN_SYRIAC = 96; // 0x60 field public static final int WOLEAI = 155; // 0x9b + field public static final int YEZIDI = 192; // 0xc0 field public static final int YI = 41; // 0x29 field public static final int ZANABAZAR_SQUARE = 177; // 0xb1 } @@ -22518,6 +22544,7 @@ package android.icu.util { field public static final android.icu.util.VersionInfo UNICODE_11_0; field public static final android.icu.util.VersionInfo UNICODE_12_0; field public static final android.icu.util.VersionInfo UNICODE_12_1; + field public static final android.icu.util.VersionInfo UNICODE_13_0; field public static final android.icu.util.VersionInfo UNICODE_1_0; field public static final android.icu.util.VersionInfo UNICODE_1_0_1; field public static final android.icu.util.VersionInfo UNICODE_1_1_0; @@ -28327,7 +28354,10 @@ package android.media.tv { method public int getVideoHeight(); method public float getVideoPixelAspectRatio(); method public int getVideoWidth(); + method public boolean isAudioDescription(); method public boolean isEncrypted(); + method public boolean isHardOfHearing(); + method public boolean isSpokenSubtitle(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvTrackInfo> CREATOR; field public static final int TYPE_AUDIO = 0; // 0x0 @@ -28339,11 +28369,14 @@ package android.media.tv { ctor public TvTrackInfo.Builder(int, @NonNull String); method public android.media.tv.TvTrackInfo build(); method public android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int); + method @NonNull public android.media.tv.TvTrackInfo.Builder setAudioDescription(boolean); method public android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int); method public android.media.tv.TvTrackInfo.Builder setDescription(CharSequence); method @NonNull public android.media.tv.TvTrackInfo.Builder setEncrypted(boolean); method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle); + method @NonNull public android.media.tv.TvTrackInfo.Builder setHardOfHearing(boolean); method public android.media.tv.TvTrackInfo.Builder setLanguage(String); + method @NonNull public android.media.tv.TvTrackInfo.Builder setSpokenSubtitle(boolean); method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte); method public android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float); method public android.media.tv.TvTrackInfo.Builder setVideoHeight(int); @@ -28655,6 +28688,37 @@ package android.net { field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR; } + public class ConnectivityDiagnosticsManager { + method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback); + method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback); + field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1 + field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2 + } + + public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback { + ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback(); + method public void onConnectivityReport(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport); + method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport); + method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean); + } + + public static class ConnectivityDiagnosticsManager.ConnectivityReport { + ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle); + field @NonNull public final android.os.PersistableBundle additionalInfo; + field @NonNull public final android.net.LinkProperties linkProperties; + field @NonNull public final android.net.Network network; + field @NonNull public final android.net.NetworkCapabilities networkCapabilities; + field public final long reportTimestamp; + } + + public static class ConnectivityDiagnosticsManager.DataStallReport { + ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.os.PersistableBundle); + field public final int detectionMethod; + field @NonNull public final android.net.Network network; + field public final long reportTimestamp; + field @NonNull public final android.os.PersistableBundle stallDetails; + } + public class ConnectivityManager { method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public boolean bindProcessToNetwork(@Nullable android.net.Network); @@ -28759,6 +28823,7 @@ package android.net { ctor public DhcpInfo(); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR; field public int dns1; field public int dns2; field public int gateway; @@ -28888,6 +28953,7 @@ package android.net { method public boolean addRoute(@NonNull android.net.RouteInfo); method public void clear(); method public int describeContents(); + method @Nullable public java.net.Inet4Address getDhcpServerAddress(); method @NonNull public java.util.List<java.net.InetAddress> getDnsServers(); method @Nullable public String getDomains(); method @Nullable public android.net.ProxyInfo getHttpProxy(); @@ -28899,6 +28965,7 @@ package android.net { method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(); method public boolean isPrivateDnsActive(); method public boolean isWakeOnLanSupported(); + method public void setDhcpServerAddress(@Nullable java.net.Inet4Address); method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>); method public void setDomains(@Nullable String); method public void setHttpProxy(@Nullable android.net.ProxyInfo); @@ -29123,9 +29190,10 @@ package android.net { method public android.net.NetworkRequest.Builder addCapability(int); method public android.net.NetworkRequest.Builder addTransportType(int); method public android.net.NetworkRequest build(); + method @NonNull public android.net.NetworkRequest.Builder clearCapabilities(); method public android.net.NetworkRequest.Builder removeCapability(int); method public android.net.NetworkRequest.Builder removeTransportType(int); - method public android.net.NetworkRequest.Builder setNetworkSpecifier(String); + method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String); method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); } @@ -29224,6 +29292,19 @@ package android.net { method public void onStopped(); } + public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + method public int describeContents(); + method public int getSubscriptionId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TelephonyNetworkSpecifier> CREATOR; + } + + public static final class TelephonyNetworkSpecifier.Builder { + ctor public TelephonyNetworkSpecifier.Builder(); + method @NonNull public android.net.TelephonyNetworkSpecifier build(); + method @NonNull public android.net.TelephonyNetworkSpecifier.Builder setSubscriptionId(int); + } + public class TrafficStats { ctor public TrafficStats(); method public static void clearThreadStatsTag(); @@ -29637,6 +29718,7 @@ package android.net.sip { method public void close(); method public void continueCall(int) throws android.net.sip.SipException; method public void endCall() throws android.net.sip.SipException; + method @Nullable public android.net.rtp.AudioGroup getAudioGroup(); method public android.net.sip.SipProfile getLocalProfile(); method public android.net.sip.SipProfile getPeerProfile(); method public int getState(); @@ -29647,6 +29729,7 @@ package android.net.sip { method public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException; method public void sendDtmf(int); method public void sendDtmf(int, android.os.Message); + method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup); method public void setListener(android.net.sip.SipAudioCall.Listener); method public void setListener(android.net.sip.SipAudioCall.Listener, boolean); method public void setSpeakerMode(boolean); @@ -29695,6 +29778,7 @@ package android.net.sip { method public void close(String) throws android.net.sip.SipException; method public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException; method public static String getCallId(android.content.Intent); + method @NonNull public java.util.List<android.net.sip.SipProfile> getListOfProfiles() throws android.net.sip.SipException; method public static String getOfferSessionDescription(android.content.Intent); method public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException; method public static boolean isApiSupported(android.content.Context); @@ -29712,6 +29796,11 @@ package android.net.sip { method public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; method public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException; method public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; + field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED"; + field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL"; + field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE"; + field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP"; + field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP"; field public static final String EXTRA_CALL_ID = "android:sipCallID"; field public static final String EXTRA_OFFER_SD = "android:sipOfferSD"; field public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65 @@ -29721,6 +29810,7 @@ package android.net.sip { method public int describeContents(); method public String getAuthUserName(); method public boolean getAutoRegistration(); + method public int getCallingUid(); method public String getDisplayName(); method public String getPassword(); method public int getPort(); @@ -29731,6 +29821,7 @@ package android.net.sip { method public String getSipDomain(); method public String getUriString(); method public String getUserName(); + method public void setCallingUid(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR; } @@ -35218,7 +35309,9 @@ package android.os { method public int describeContents(); method @Nullable public android.os.PersistableBundle getPersistableBundle(@Nullable String); method public void putPersistableBundle(@Nullable String, @Nullable android.os.PersistableBundle); + method @NonNull public static android.os.PersistableBundle readFromStream(@NonNull java.io.InputStream) throws java.io.IOException; method public void writeToParcel(android.os.Parcel, int); + method public void writeToStream(@NonNull java.io.OutputStream) throws java.io.IOException; field @NonNull public static final android.os.Parcelable.Creator<android.os.PersistableBundle> CREATOR; field public static final android.os.PersistableBundle EMPTY; } @@ -40836,6 +40929,7 @@ package android.se.omapi { public final class SEService { ctor public SEService(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.se.omapi.SEService.OnConnectedListener); method @NonNull public android.se.omapi.Reader[] getReaders(); + method @NonNull public android.se.omapi.Reader getUiccReader(int); method @NonNull public String getVersion(); method public boolean isConnected(); method public void shutdown(); @@ -40973,6 +41067,138 @@ package android.security { } +package android.security.identity { + + public class AccessControlProfile { + } + + public static final class AccessControlProfile.Builder { + ctor public AccessControlProfile.Builder(@NonNull android.security.identity.AccessControlProfileId); + method @NonNull public android.security.identity.AccessControlProfile build(); + method @NonNull public android.security.identity.AccessControlProfile.Builder setReaderCertificate(@NonNull java.security.cert.X509Certificate); + method @NonNull public android.security.identity.AccessControlProfile.Builder setUserAuthenticationRequired(boolean); + method @NonNull public android.security.identity.AccessControlProfile.Builder setUserAuthenticationTimeout(long); + } + + public class AccessControlProfileId { + ctor public AccessControlProfileId(int); + method public int getId(); + } + + public class AlreadyPersonalizedException extends android.security.identity.IdentityCredentialException { + ctor public AlreadyPersonalizedException(@NonNull String); + ctor public AlreadyPersonalizedException(@NonNull String, @NonNull Throwable); + } + + public class CipherSuiteNotSupportedException extends android.security.identity.IdentityCredentialException { + ctor public CipherSuiteNotSupportedException(@NonNull String); + ctor public CipherSuiteNotSupportedException(@NonNull String, @NonNull Throwable); + } + + public class DocTypeNotSupportedException extends android.security.identity.IdentityCredentialException { + ctor public DocTypeNotSupportedException(@NonNull String); + ctor public DocTypeNotSupportedException(@NonNull String, @NonNull Throwable); + } + + public class EphemeralPublicKeyNotFoundException extends android.security.identity.IdentityCredentialException { + ctor public EphemeralPublicKeyNotFoundException(@NonNull String); + ctor public EphemeralPublicKeyNotFoundException(@NonNull String, @NonNull Throwable); + } + + public abstract class IdentityCredential { + method @NonNull public abstract java.security.KeyPair createEphemeralKeyPair(); + method @NonNull public abstract byte[] decryptMessageFromReader(@NonNull byte[]) throws android.security.identity.MessageDecryptionException; + method @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]); + method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getAuthKeysNeedingCertification(); + method @NonNull public abstract int[] getAuthenticationDataUsageCount(); + method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain(); + method @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException; + method public abstract void setAllowUsingExhaustedKeys(boolean); + method public abstract void setAvailableAuthenticationKeys(int, int); + method public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException; + method public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException; + } + + public class IdentityCredentialException extends java.lang.Exception { + ctor public IdentityCredentialException(@NonNull String); + ctor public IdentityCredentialException(@NonNull String, @NonNull Throwable); + } + + public abstract class IdentityCredentialStore { + method @NonNull public abstract android.security.identity.WritableIdentityCredential createCredential(@NonNull String, @NonNull String) throws android.security.identity.AlreadyPersonalizedException, android.security.identity.DocTypeNotSupportedException; + method @Nullable public abstract byte[] deleteCredentialByName(@NonNull String); + method @Nullable public abstract android.security.identity.IdentityCredential getCredentialByName(@NonNull String, int) throws android.security.identity.CipherSuiteNotSupportedException; + method @Nullable public static android.security.identity.IdentityCredentialStore getDirectAccessInstance(@NonNull android.content.Context); + method @Nullable public static android.security.identity.IdentityCredentialStore getInstance(@NonNull android.content.Context); + method @NonNull public abstract String[] getSupportedDocTypes(); + field public static final int CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1; // 0x1 + } + + public class InvalidReaderSignatureException extends android.security.identity.IdentityCredentialException { + ctor public InvalidReaderSignatureException(@NonNull String); + ctor public InvalidReaderSignatureException(@NonNull String, @NonNull Throwable); + } + + public class InvalidRequestMessageException extends android.security.identity.IdentityCredentialException { + ctor public InvalidRequestMessageException(@NonNull String); + ctor public InvalidRequestMessageException(@NonNull String, @NonNull Throwable); + } + + public class MessageDecryptionException extends android.security.identity.IdentityCredentialException { + ctor public MessageDecryptionException(@NonNull String); + ctor public MessageDecryptionException(@NonNull String, @NonNull Throwable); + } + + public class NoAuthenticationKeyAvailableException extends android.security.identity.IdentityCredentialException { + ctor public NoAuthenticationKeyAvailableException(@NonNull String); + ctor public NoAuthenticationKeyAvailableException(@NonNull String, @NonNull Throwable); + } + + public class PersonalizationData { + } + + public static final class PersonalizationData.Builder { + ctor public PersonalizationData.Builder(); + method @NonNull public android.security.identity.PersonalizationData.Builder addAccessControlProfile(@NonNull android.security.identity.AccessControlProfile); + method @NonNull public android.security.identity.PersonalizationData build(); + method @NonNull public android.security.identity.PersonalizationData.Builder setEntry(@NonNull String, @NonNull String, @NonNull java.util.Collection<android.security.identity.AccessControlProfileId>, @NonNull byte[]); + } + + public abstract class ResultData { + method @NonNull public abstract byte[] getAuthenticatedData(); + method @Nullable public abstract byte[] getEntry(@NonNull String, @NonNull String); + method @Nullable public abstract java.util.Collection<java.lang.String> getEntryNames(@NonNull String); + method @Nullable public abstract byte[] getMessageAuthenticationCode(); + method @NonNull public abstract java.util.Collection<java.lang.String> getNamespaceNames(); + method @Nullable public abstract java.util.Collection<java.lang.String> getRetrievedEntryNames(@NonNull String); + method @NonNull public abstract byte[] getStaticAuthenticationData(); + method public abstract int getStatus(@NonNull String, @NonNull String); + field public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3; // 0x3 + field public static final int STATUS_NOT_REQUESTED = 2; // 0x2 + field public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6; // 0x6 + field public static final int STATUS_NO_SUCH_ENTRY = 1; // 0x1 + field public static final int STATUS_OK = 0; // 0x0 + field public static final int STATUS_READER_AUTHENTICATION_FAILED = 5; // 0x5 + field public static final int STATUS_USER_AUTHENTICATION_FAILED = 4; // 0x4 + } + + public class SessionTranscriptMismatchException extends android.security.identity.IdentityCredentialException { + ctor public SessionTranscriptMismatchException(@NonNull String); + ctor public SessionTranscriptMismatchException(@NonNull String, @NonNull Throwable); + } + + public class UnknownAuthenticationKeyException extends android.security.identity.IdentityCredentialException { + ctor public UnknownAuthenticationKeyException(@NonNull String); + ctor public UnknownAuthenticationKeyException(@NonNull String, @NonNull Throwable); + } + + public abstract class WritableIdentityCredential { + method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain(@NonNull byte[]); + method @NonNull public abstract byte[] personalize(@NonNull android.security.identity.PersonalizationData); + } + +} + package android.security.keystore { public class KeyExpiredException extends java.security.InvalidKeyException { @@ -42575,6 +42801,7 @@ package android.system { method public static void execve(String, String[], String[]) throws android.system.ErrnoException; method public static void fchmod(java.io.FileDescriptor, int) throws android.system.ErrnoException; method public static void fchown(java.io.FileDescriptor, int, int) throws android.system.ErrnoException; + method public static int fcntlInt(@NonNull java.io.FileDescriptor, int, int) throws android.system.ErrnoException; method public static void fdatasync(java.io.FileDescriptor) throws android.system.ErrnoException; method public static android.system.StructStat fstat(java.io.FileDescriptor) throws android.system.ErrnoException; method public static android.system.StructStatVfs fstatvfs(java.io.FileDescriptor) throws android.system.ErrnoException; @@ -43255,6 +43482,7 @@ package android.telecom { method public java.util.List<android.telecom.Call> getChildren(); method public java.util.List<android.telecom.Call> getConferenceableCalls(); method public android.telecom.Call.Details getDetails(); + method @Nullable public android.telecom.Call getGenericConferenceActiveChildCall(); method public android.telecom.Call getParent(); method public String getRemainingPostDialSequence(); method @Nullable public android.telecom.Call.RttCall getRttCall(); @@ -43338,6 +43566,7 @@ package android.telecom { method public int getCallerDisplayNamePresentation(); method public int getCallerNumberVerificationStatus(); method public final long getConnectTimeMillis(); + method @Nullable public String getContactDisplayName(); method public long getCreationTimeMillis(); method public android.telecom.DisconnectCause getDisconnectCause(); method public android.os.Bundle getExtras(); @@ -44201,6 +44430,8 @@ package android.telecom { package android.telephony { public final class AccessNetworkConstants { + field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2 + field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1 } public static final class AccessNetworkConstants.AccessNetworkType { @@ -44375,6 +44606,9 @@ package android.telephony { field public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1; // 0xffffffff field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX"; field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX"; + field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int"; + field public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string"; + field public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int"; field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array"; field public static final String KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrq_thresholds_int_array"; field public static final String KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY = "5g_nr_sssinr_thresholds_int_array"; @@ -44388,18 +44622,32 @@ package android.telephony { field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool"; field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool"; field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool"; - field public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool"; + field public static final String KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL = "allow_video_calling_fallback_bool"; + field public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL = "always_show_data_rat_icon_bool"; + field @Deprecated public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool"; + field public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN = "always_show_primary_signal_bar_in_opportunistic_network_boolean"; field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool"; + field public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array"; field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool"; field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool"; field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool"; field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool"; field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array"; + field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string"; + field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool"; field public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool"; field public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL = "carrier_app_required_during_setup_bool"; field public static final String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app"; + field public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY = "carrier_certificate_string_array"; + field public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool"; field public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string"; field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings"; + field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY = "carrier_default_actions_on_dcfailure_string_array"; + field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE = "carrier_default_actions_on_default_network_available_string_array"; + field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY = "carrier_default_actions_on_redirection_string_array"; + field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET = "carrier_default_actions_on_reset_string_array"; + field public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY = "carrier_default_redirection_url_string_array"; + field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL = "carrier_default_wfc_ims_enabled_bool"; field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int"; field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = "carrier_default_wfc_ims_roaming_mode_int"; field @Deprecated public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool"; @@ -44411,11 +44659,14 @@ package android.telephony { field public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int"; field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool"; field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string"; + field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool"; + field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool"; field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool"; field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool"; field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool"; + field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool"; field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool"; field public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool"; @@ -44429,6 +44680,7 @@ package android.telephony { field public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; field public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int"; field public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; + field public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool"; field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool"; field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string"; field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string"; @@ -44438,6 +44690,7 @@ package android.telephony { field public static final String KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING = "config_ims_rcs_package_override_string"; field public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string"; field public static final String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool"; + field public static final String KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm"; field public static final String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool"; field public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool"; field public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long"; @@ -44449,6 +44702,7 @@ package android.telephony { field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string"; field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array"; field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; + field public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool"; field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool"; field public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array"; field public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool"; @@ -44458,9 +44712,13 @@ package android.telephony { field public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool"; field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool"; field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool"; + field public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool"; + field public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool"; + field public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int"; field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array"; field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool"; field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool"; + field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int"; field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool"; field public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int"; field public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array"; @@ -44469,13 +44727,17 @@ package android.telephony { field public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool"; field public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool"; field public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool"; + field public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool"; field public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool"; field public static final String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool"; field public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool"; + field public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = "ignore_data_enabled_changed_for_video_calls"; + field public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool"; field public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool"; field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int"; field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int"; field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool"; + field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool"; field public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array"; field public static final String KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "lte_rssnr_thresholds_int_array"; field public static final String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool"; @@ -44484,6 +44746,7 @@ package android.telephony { field public static final String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars"; field public static final String KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL = "allowAttachAudio"; field public static final String KEY_MMS_APPEND_TRANSACTION_ID_BOOL = "enabledTransID"; + field public static final String KEY_MMS_CLOSE_CONNECTION_BOOL = "mmsCloseConnection"; field public static final String KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING = "emailGatewayNumber"; field public static final String KEY_MMS_GROUP_MMS_ENABLED_BOOL = "enableGroupMms"; field public static final String KEY_MMS_HTTP_PARAMS_STRING = "httpParams"; @@ -44511,6 +44774,7 @@ package android.telephony { field public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl"; field public static final String KEY_MMS_USER_AGENT_STRING = "userAgent"; field public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int"; + field public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network"; field public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array"; field public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool"; field public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG = "opportunistic_network_data_switch_hysteresis_time_long"; @@ -44524,15 +44788,24 @@ package android.telephony { field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool"; field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array"; field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string"; + field public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array"; + field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array"; field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool"; field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool"; field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool"; + field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; + field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; + field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool"; field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool"; + field public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string"; field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool"; field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool"; + field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool"; field public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool"; field public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool"; + field public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL = "show_video_call_charges_alert_dialog_bool"; + field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool"; field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool"; field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; @@ -44541,14 +44814,20 @@ package android.telephony { field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool"; field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool"; field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool"; + field public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = "support_enhanced_call_blocking_bool"; + field public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL = "support_ims_conference_event_package_bool"; field public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool"; field public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool"; + field public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool"; + field public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = "support_tdscdma_roaming_networks_string_array"; field public static final String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool"; field public static final String KEY_TTY_SUPPORTED_BOOL = "tty_supported_bool"; + field public static final String KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY = "unloggable_numbers_string_array"; field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool"; field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool"; field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool"; + field public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool"; field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool"; field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool"; field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int"; @@ -44561,6 +44840,8 @@ package android.telephony { field public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool"; field public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool"; field public static final String KEY_VVM_TYPE_STRING = "vvm_type_string"; + field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string"; + field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool"; field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool"; } @@ -44663,7 +44944,8 @@ package android.telephony { method public int getCellConnectionStatus(); method @NonNull public abstract android.telephony.CellIdentity getCellIdentity(); method @NonNull public abstract android.telephony.CellSignalStrength getCellSignalStrength(); - method public long getTimeStamp(); + method @Deprecated public long getTimeStamp(); + method public long getTimestampNanos(); method public boolean isRegistered(); field public static final int CONNECTION_NONE = 0; // 0x0 field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1 @@ -44898,6 +45180,35 @@ package android.telephony { field @Deprecated public static final int UNKNOWN_RSSI = 99; // 0x63 } + public final class NetworkRegistrationInfo implements android.os.Parcelable { + method public int describeContents(); + method public int getAccessNetworkTechnology(); + method @NonNull public java.util.List<java.lang.Integer> getAvailableServices(); + method @Nullable public android.telephony.CellIdentity getCellIdentity(); + method public int getDomain(); + method public int getNrState(); + method public int getTransportType(); + method public boolean isRegistered(); + method public boolean isRoaming(); + method public boolean isSearching(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR; + field public static final int DOMAIN_CS = 1; // 0x1 + field public static final int DOMAIN_CS_PS = 3; // 0x3 + field public static final int DOMAIN_PS = 2; // 0x2 + field public static final int DOMAIN_UNKNOWN = 0; // 0x0 + field public static final int NR_STATE_CONNECTED = 3; // 0x3 + field public static final int NR_STATE_NONE = 0; // 0x0 + field public static final int NR_STATE_NOT_RESTRICTED = 2; // 0x2 + field public static final int NR_STATE_RESTRICTED = 1; // 0x1 + field public static final int SERVICE_TYPE_DATA = 2; // 0x2 + field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 + field public static final int SERVICE_TYPE_SMS = 3; // 0x3 + field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0 + field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 + field public static final int SERVICE_TYPE_VOICE = 1; // 0x1 + } + public class NetworkScan { method public void stopScan(); field public static final int ERROR_INTERRUPTED = 10002; // 0x2712 @@ -45013,6 +45324,7 @@ package android.telephony { method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo); method public void onMessageWaitingIndicatorChanged(boolean); method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState); + method public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int); method public void onServiceStateChanged(android.telephony.ServiceState); method @Deprecated public void onSignalStrengthChanged(int); method public void onSignalStrengthsChanged(android.telephony.SignalStrength); @@ -45029,7 +45341,8 @@ package android.telephony { field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000 field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4 field public static final int LISTEN_NONE = 0; // 0x0 - field @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000 + field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000 + field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000 field public static final int LISTEN_SERVICE_STATE = 1; // 0x1 field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2 field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100 @@ -45068,11 +45381,13 @@ package android.telephony { method public int getChannelNumber(); method public int getDuplexMode(); method public boolean getIsManualSelection(); + method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList(); method public String getOperatorAlphaLong(); method public String getOperatorAlphaShort(); method public String getOperatorNumeric(); method public boolean getRoaming(); method public int getState(); + method public boolean isSearching(); method public void setIsManualSelection(boolean); method public void setOperatorName(String, String, String); method public void setRoaming(boolean); @@ -45103,8 +45418,10 @@ package android.telephony { method @Deprecated public int getGsmBitErrorRate(); method @Deprecated public int getGsmSignalStrength(); method public int getLevel(); + method public long getTimestampNanos(); method @Deprecated public boolean isGsm(); method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrength> CREATOR; field public static final int INVALID = 2147483647; // 0x7fffffff } @@ -45113,7 +45430,7 @@ package android.telephony { method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent); method public java.util.ArrayList<java.lang.String> divideMessage(String); method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent); - method public android.os.Bundle getCarrierConfigValues(); + method @Nullable public android.os.Bundle getCarrierConfigValues(); method public static android.telephony.SmsManager getDefault(); method public static int getDefaultSmsSubscriptionId(); method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int); @@ -45251,6 +45568,7 @@ package android.telephony { method public byte[] getPdu(); method public int getProtocolIdentifier(); method public String getPseudoSubject(); + method @Nullable public String getRecipientAddress(); method public String getServiceCenterAddress(); method public int getStatus(); method public int getStatusOnIcc(); @@ -45322,6 +45640,7 @@ package android.telephony { public class SubscriptionManager { method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); + method public void addOnSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid); method public boolean canManageSubscription(android.telephony.SubscriptionInfo); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>); @@ -45387,6 +45706,7 @@ package android.telephony { method public long getDataLimitBytes(); method public long getDataUsageBytes(); method public long getDataUsageTime(); + method @Nullable public int[] getNetworkTypes(); method @Nullable public CharSequence getSummary(); method @Nullable public CharSequence getTitle(); method public void writeToParcel(android.os.Parcel, int); @@ -45406,6 +45726,7 @@ package android.telephony { method public static android.telephony.SubscriptionPlan.Builder createRecurring(java.time.ZonedDateTime, java.time.Period); method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int); method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long); + method @NonNull public android.telephony.SubscriptionPlan.Builder setNetworkTypes(@Nullable int[]); method public android.telephony.SubscriptionPlan.Builder setSummary(@Nullable CharSequence); method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence); } @@ -45447,6 +45768,7 @@ package android.telephony { method public String getNetworkCountryIso(); method public String getNetworkOperator(); method public String getNetworkOperatorName(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getNetworkSelectionMode(); method public String getNetworkSpecifier(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getNetworkType(); method @Deprecated public int getPhoneCount(); @@ -45477,12 +45799,12 @@ package android.telephony { method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); method public boolean hasCarrierPrivileges(); method public boolean hasIccCard(); - method public boolean iccCloseLogicalChannel(int); - method public byte[] iccExchangeSimIO(int, int, int, int, int, String); + method @Deprecated public boolean iccCloseLogicalChannel(int); + method @Deprecated public byte[] iccExchangeSimIO(int, int, int, int, int, String); method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String); - method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int); - method public String iccTransmitApduBasicChannel(int, int, int, int, int, String); - method public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String); + method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int); + method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String); + method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String); method public boolean isConcurrentVoiceAndDataSupported(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled(); @@ -45500,7 +45822,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback); method public void sendDialerSpecialCode(String); - method public String sendEnvelopeWithStatus(String); + method @Deprecated public String sendEnvelopeWithStatus(String); method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean); @@ -45579,6 +45901,9 @@ package android.telephony { field public static final int MULTISIM_ALLOWED = 0; // 0x0 field public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2; // 0x2 field public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1; // 0x1 + field public static final int NETWORK_SELECTION_MODE_AUTO = 1; // 0x1 + field public static final int NETWORK_SELECTION_MODE_MANUAL = 2; // 0x2 + field public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; // 0x0 field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 field public static final int NETWORK_TYPE_CDMA = 4; // 0x4 field public static final int NETWORK_TYPE_EDGE = 2; // 0x2 @@ -45601,6 +45926,7 @@ package android.telephony { field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0 field public static final int PHONE_TYPE_CDMA = 2; // 0x2 field public static final int PHONE_TYPE_GSM = 1; // 0x1 + field public static final int PHONE_TYPE_IMS = 5; // 0x5 field public static final int PHONE_TYPE_NONE = 0; // 0x0 field public static final int PHONE_TYPE_SIP = 3; // 0x3 field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2 @@ -45989,6 +46315,37 @@ package android.telephony.gsm { package android.telephony.ims { + public final class ImsException extends java.lang.Exception { + method public int getCode(); + field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1 + field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0 + field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2 + } + + public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { + method @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isAdvancedCallingSettingEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isTtyOverVolteEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiRoamingSettingEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVtSettingEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback); + field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1 + field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0 + field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2 + } + + public static class ImsMmTelManager.CapabilityCallback { + ctor public ImsMmTelManager.CapabilityCallback(); + method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities); + } + public final class ImsReasonInfo implements android.os.Parcelable { ctor public ImsReasonInfo(int, int, @Nullable String); method public int describeContents(); @@ -46172,6 +46529,38 @@ package android.telephony.ims { field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2 } + public interface RegistrationManager { + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); + field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0 + field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2 + field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1 + } + + public static class RegistrationManager.RegistrationCallback { + ctor public RegistrationManager.RegistrationCallback(); + method public void onRegistered(int); + method public void onRegistering(int); + method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo); + method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo); + } + +} + +package android.telephony.ims.feature { + + public class MmTelFeature { + } + + public static class MmTelFeature.MmTelCapabilities { + field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 + field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 + field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 + field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1 + } + } package android.telephony.mbms { @@ -49197,6 +49586,71 @@ package android.util { } +package android.util.proto { + + public final class ProtoOutputStream { + ctor public ProtoOutputStream(); + ctor public ProtoOutputStream(int); + ctor public ProtoOutputStream(@NonNull java.io.OutputStream); + method public static int checkFieldId(long, long); + method public void dump(@NonNull String); + method public void end(long); + method public void flush(); + method @NonNull public byte[] getBytes(); + method @Nullable public static String getFieldCountString(long); + method @NonNull public static String getFieldIdString(long); + method @Nullable public static String getFieldTypeString(long); + method public int getRawSize(); + method @Nullable public static String getWireTypeString(int); + method public static long makeFieldId(int, long); + method public static long makeToken(int, boolean, int, int, int); + method public long start(long); + method @NonNull public static String token2String(long); + method public void write(long, double); + method public void write(long, float); + method public void write(long, int); + method public void write(long, long); + method public void write(long, boolean); + method public void write(long, @Nullable String); + method public void write(long, @Nullable byte[]); + method public void writeTag(int, int); + field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L + field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L + field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L + field public static final int FIELD_COUNT_SHIFT = 40; // 0x28 + field public static final long FIELD_COUNT_SINGLE = 1099511627776L; // 0x10000000000L + field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L + field public static final int FIELD_ID_SHIFT = 3; // 0x3 + field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L + field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L + field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L + field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L + field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L + field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L + field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L + field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L + field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L + field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L + field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L + field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L + field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L + field public static final int FIELD_TYPE_SHIFT = 32; // 0x20 + field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L + field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L + field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L + field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L + field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L + field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4 + field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5 + field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1 + field public static final int WIRE_TYPE_LENGTH_DELIMITED = 2; // 0x2 + field public static final int WIRE_TYPE_MASK = 7; // 0x7 + field public static final int WIRE_TYPE_START_GROUP = 3; // 0x3 + field public static final int WIRE_TYPE_VARINT = 0; // 0x0 + } + +} + package android.view { public abstract class AbsSavedState implements android.os.Parcelable { @@ -70690,6 +71144,18 @@ package java.util { method public int lastIndexOf(@Nullable Object); method @NonNull public java.util.ListIterator<E> listIterator(); method @NonNull public java.util.ListIterator<E> listIterator(int); + method @NonNull public static <E> java.util.List<E> of(); + method @NonNull public static <E> java.util.List<E> of(@NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull @java.lang.SafeVarargs public static <E> java.util.List<E> of(@NonNull E...); method public E remove(int); method public default void replaceAll(@NonNull java.util.function.UnaryOperator<E>); method public E set(int, E); @@ -70844,6 +71310,7 @@ package java.util { method @Nullable public default V computeIfPresent(K, @NonNull java.util.function.BiFunction<? super K,? super V,? extends V>); method public boolean containsKey(@Nullable Object); method public boolean containsValue(@Nullable Object); + method @NonNull public static <K, V> java.util.Map.Entry<K,V> entry(@NonNull K, @NonNull V); method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet(); method public boolean equals(@Nullable Object); method public default void forEach(@NonNull java.util.function.BiConsumer<? super K,? super V>); @@ -70853,6 +71320,18 @@ package java.util { method public boolean isEmpty(); method @NonNull public java.util.Set<K> keySet(); method @Nullable public default V merge(K, @NonNull V, @NonNull java.util.function.BiFunction<? super V,? super V,? extends V>); + method @NonNull public static <K, V> java.util.Map<K,V> of(); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull @java.lang.SafeVarargs public static <K, V> java.util.Map<K,V> ofEntries(@NonNull java.util.Map.Entry<? extends K,? extends V>...); method @Nullable public V put(K, V); method public void putAll(@NonNull java.util.Map<? extends K,? extends V>); method @Nullable public default V putIfAbsent(K, V); @@ -70934,6 +71413,9 @@ package java.util { } public final class Objects { + method public static int checkFromIndexSize(int, int, int); + method public static int checkFromToIndex(int, int, int); + method public static int checkIndex(int, int); method public static <T> int compare(T, T, @NonNull java.util.Comparator<? super T>); method public static boolean deepEquals(@Nullable Object, @Nullable Object); method public static boolean equals(@Nullable Object, @Nullable Object); @@ -70944,6 +71426,8 @@ package java.util { method @NonNull public static <T> T requireNonNull(@Nullable T); method @NonNull public static <T> T requireNonNull(@Nullable T, @NonNull String); method @NonNull public static <T> T requireNonNull(@Nullable T, @NonNull java.util.function.Supplier<java.lang.String>); + method @NonNull public static <T> T requireNonNullElse(@Nullable T, @NonNull T); + method @NonNull public static <T> T requireNonNullElseGet(@Nullable T, @NonNull java.util.function.Supplier<? extends T>); method @NonNull public static String toString(@Nullable Object); method @NonNull public static String toString(@Nullable Object, @NonNull String); } @@ -71248,6 +71732,18 @@ package java.util { } public interface Set<E> extends java.util.Collection<E> { + method @NonNull public static <E> java.util.Set<E> of(); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull @java.lang.SafeVarargs public static <E> java.util.Set<E> of(@NonNull E...); } public class SimpleTimeZone extends java.util.TimeZone { @@ -72186,6 +72682,29 @@ package java.util.concurrent { method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService); } + public final class Flow { + method public static int defaultBufferSize(); + } + + public static interface Flow.Processor<T, R> extends java.util.concurrent.Flow.Subscriber<T> java.util.concurrent.Flow.Publisher<R> { + } + + @java.lang.FunctionalInterface public static interface Flow.Publisher<T> { + method public void subscribe(java.util.concurrent.Flow.Subscriber<? super T>); + } + + public static interface Flow.Subscriber<T> { + method public void onComplete(); + method public void onError(Throwable); + method public void onNext(T); + method public void onSubscribe(java.util.concurrent.Flow.Subscription); + } + + public static interface Flow.Subscription { + method public void cancel(); + method public void request(long); + } + public class ForkJoinPool extends java.util.concurrent.AbstractExecutorService { ctor public ForkJoinPool(); ctor public ForkJoinPool(int); diff --git a/api/lint-baseline.txt b/api/lint-baseline.txt index 27204985d8d9..5c31f41e2e3c 100644 --- a/api/lint-baseline.txt +++ b/api/lint-baseline.txt @@ -485,10 +485,20 @@ HiddenSuperclass: android.util.StatsLog: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CHORASMIAN: + Missing nullability on field `CHORASMIAN` in class `class android.icu.lang.UCharacter.UnicodeBlock` +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G: + Missing nullability on field `CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G` in class `class android.icu.lang.UCharacter.UnicodeBlock` +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#DIVES_AKURU: + Missing nullability on field `DIVES_AKURU` in class `class android.icu.lang.UCharacter.UnicodeBlock` MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS: MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#ELYMAIC: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#KHITAN_SMALL_SCRIPT: + +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#LISU_SUPPLEMENT: + MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#NANDINAGARI: MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#NYIAKENG_PUACHUE_HMONG: @@ -499,26 +509,34 @@ MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#SMALL_KANA_EXTENSIO MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#SYMBOLS_FOR_LEGACY_COMPUTING: + MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#TAMIL_SUPPLEMENT: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#TANGUT_SUPPLEMENT: + MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#WANCHO: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#YEZIDI: + MissingNullability: android.icu.text.DateTimePatternGenerator#getFieldDisplayName(int, android.icu.text.DateTimePatternGenerator.DisplayWidth): MissingNullability: android.icu.text.DateTimePatternGenerator#getFieldDisplayName(int, android.icu.text.DateTimePatternGenerator.DisplayWidth) parameter #1: MissingNullability: android.icu.util.MeasureUnit#ATMOSPHERE: - Missing nullability on field `ATMOSPHERE` in class `class android.icu.util.MeasureUnit` + MissingNullability: android.icu.util.MeasureUnit#PERCENT: - Missing nullability on field `PERCENT` in class `class android.icu.util.MeasureUnit` + MissingNullability: android.icu.util.MeasureUnit#PERMILLE: - Missing nullability on field `PERMILLE` in class `class android.icu.util.MeasureUnit` + MissingNullability: android.icu.util.MeasureUnit#PETABYTE: - Missing nullability on field `PETABYTE` in class `class android.icu.util.MeasureUnit` + MissingNullability: android.icu.util.VersionInfo#UNICODE_12_0: MissingNullability: android.icu.util.VersionInfo#UNICODE_12_1: +MissingNullability: android.icu.util.VersionInfo#UNICODE_13_0: + Missing nullability on field `UNICODE_13_0` in class `class android.icu.util.VersionInfo` RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler): diff --git a/api/module-app-current.txt b/api/module-app-current.txt new file mode 100644 index 000000000000..4307e675e431 --- /dev/null +++ b/api/module-app-current.txt @@ -0,0 +1,9 @@ +// Signature format: 2.0 +package android.app { + + public final class NotificationChannel implements android.os.Parcelable { + method public void setBlockableSystem(boolean); + } + +} + diff --git a/api/module-app-removed.txt b/api/module-app-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/api/module-app-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt new file mode 100644 index 000000000000..c657e0049670 --- /dev/null +++ b/api/module-lib-current.txt @@ -0,0 +1,148 @@ +// Signature format: 2.0 +package android.app.timedetector { + + public final class PhoneTimeSuggestion implements android.os.Parcelable { + method public void addDebugInfo(@NonNull String); + method public void addDebugInfo(@NonNull java.util.List<java.lang.String>); + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getDebugInfo(); + method public int getPhoneId(); + method @Nullable public android.os.TimestampedValue<java.lang.Long> getUtcTime(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.timedetector.PhoneTimeSuggestion> CREATOR; + } + + public static final class PhoneTimeSuggestion.Builder { + ctor public PhoneTimeSuggestion.Builder(int); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder addDebugInfo(@NonNull String); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion build(); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder setUtcTime(@Nullable android.os.TimestampedValue<java.lang.Long>); + } + + public class TimeDetector { + method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTime(@NonNull android.app.timedetector.PhoneTimeSuggestion); + } + +} + +package android.app.timezonedetector { + + public final class PhoneTimeZoneSuggestion implements android.os.Parcelable { + method public void addDebugInfo(@NonNull String); + method public void addDebugInfo(@NonNull java.util.List<java.lang.String>); + method @NonNull public static android.app.timezonedetector.PhoneTimeZoneSuggestion createEmptySuggestion(int, @NonNull String); + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getDebugInfo(); + method public int getMatchType(); + method public int getPhoneId(); + method public int getQuality(); + method @Nullable public String getZoneId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.timezonedetector.PhoneTimeZoneSuggestion> CREATOR; + field public static final int MATCH_TYPE_EMULATOR_ZONE_ID = 4; // 0x4 + field public static final int MATCH_TYPE_NA = 0; // 0x0 + field public static final int MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET = 3; // 0x3 + field public static final int MATCH_TYPE_NETWORK_COUNTRY_ONLY = 2; // 0x2 + field public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5; // 0x5 + field public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3; // 0x3 + field public static final int QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET = 2; // 0x2 + field public static final int QUALITY_NA = 0; // 0x0 + field public static final int QUALITY_SINGLE_ZONE = 1; // 0x1 + } + + public static final class PhoneTimeZoneSuggestion.Builder { + ctor public PhoneTimeZoneSuggestion.Builder(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder addDebugInfo(@NonNull String); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion build(); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setMatchType(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setQuality(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setZoneId(@Nullable String); + } + + public class TimeZoneDetector { + method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTimeZone(@NonNull android.app.timezonedetector.PhoneTimeZoneSuggestion); + } + +} + +package android.os { + + public final class TimestampedValue<T> implements android.os.Parcelable { + ctor public TimestampedValue(long, @Nullable T); + method public int describeContents(); + method public long getReferenceTimeMillis(); + method @Nullable public T getValue(); + method public static long referenceTimeDifference(@NonNull android.os.TimestampedValue<?>, @NonNull android.os.TimestampedValue<?>); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.os.TimestampedValue<?>> CREATOR; + } + +} + +package android.timezone { + + public final class CountryTimeZones { + method @Nullable public android.icu.util.TimeZone getDefaultTimeZone(); + method @Nullable public String getDefaultTimeZoneId(); + method @NonNull public java.util.List<android.timezone.CountryTimeZones.TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long); + method public boolean hasUtcZone(long); + method public boolean isDefaultTimeZoneBoosted(); + method public boolean isForCountryCode(@NonNull String); + method @Nullable public android.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(int, @Nullable Boolean, @Nullable Integer, long, @Nullable android.icu.util.TimeZone); + } + + public static final class CountryTimeZones.OffsetResult { + ctor public CountryTimeZones.OffsetResult(@NonNull android.icu.util.TimeZone, boolean); + method @NonNull public android.icu.util.TimeZone getTimeZone(); + method public boolean isOnlyMatch(); + } + + public static final class CountryTimeZones.TimeZoneMapping { + method @Nullable public android.icu.util.TimeZone getTimeZone(); + method @NonNull public String getTimeZoneId(); + } + + public class TelephonyLookup { + method @NonNull public static android.timezone.TelephonyLookup getInstance(); + method @Nullable public android.timezone.TelephonyNetworkFinder getTelephonyNetworkFinder(); + } + + public class TelephonyNetwork { + method @NonNull public String getCountryIsoCode(); + method @NonNull public String getMcc(); + method @NonNull public String getMnc(); + } + + public class TelephonyNetworkFinder { + method @Nullable public android.timezone.TelephonyNetwork findNetworkByMccMnc(@NonNull String, @NonNull String); + } + + public final class TimeZoneFinder { + method @Nullable public String getIanaVersion(); + method @NonNull public static android.timezone.TimeZoneFinder getInstance(); + method @Nullable public android.timezone.CountryTimeZones lookupCountryTimeZones(@NonNull String); + } + + public final class TzDataSetVersion { + method public static int currentFormatMajorVersion(); + method public static int currentFormatMinorVersion(); + method public int getFormatMajorVersion(); + method public int getFormatMinorVersion(); + method public int getRevision(); + method @NonNull public String getRulesVersion(); + method public static boolean isCompatibleWithThisDevice(android.timezone.TzDataSetVersion); + method @NonNull public static android.timezone.TzDataSetVersion read() throws java.io.IOException, android.timezone.TzDataSetVersion.TzDataSetException; + } + + public static class TzDataSetVersion.TzDataSetException extends java.lang.Exception { + ctor public TzDataSetVersion.TzDataSetException(String); + ctor public TzDataSetVersion.TzDataSetException(String, Throwable); + } + + public final class ZoneInfoDb { + method @NonNull public static android.timezone.ZoneInfoDb getInstance(); + method @NonNull public String getVersion(); + } + +} + diff --git a/api/module-lib-removed.txt b/api/module-lib-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/api/module-lib-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/api/system-current.txt b/api/system-current.txt index 0edf9ab40821..558907c80c13 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -8,6 +8,7 @@ package android { field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES"; field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO"; field public static final String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS"; + field public static final String ACCESS_MESSAGES_ON_ICC = "android.permission.ACCESS_MESSAGES_ON_ICC"; field public static final String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION"; field public static final String ACCESS_MTP = "android.permission.ACCESS_MTP"; field public static final String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS"; @@ -181,6 +182,7 @@ package android { field public static final String REVIEW_ACCESSIBILITY_SERVICES = "android.permission.REVIEW_ACCESSIBILITY_SERVICES"; field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS"; field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS"; + field public static final String SECURE_ELEMENT_PRIVILEGED = "android.permission.SECURE_ELEMENT_PRIVILEGED"; field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY"; field public static final String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"; field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION"; @@ -198,6 +200,7 @@ package android { field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES"; field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"; field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON"; + field public static final String SUGGEST_PHONE_TIME_AND_ZONE = "android.permission.SUGGEST_PHONE_TIME_AND_ZONE"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED"; field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE"; @@ -596,6 +599,7 @@ package android.app { public class StatusBarManager { method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo(); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean); } public static final class StatusBarManager.DisableInfo { @@ -680,6 +684,7 @@ package android.app { package android.app.admin { public class DevicePolicyManager { + method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwnerNameOnAnyUser(); @@ -1162,6 +1167,7 @@ package android.app.role { method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String); method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @Nullable public String getDefaultSmsPackage(int); method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle); @@ -1205,6 +1211,10 @@ package android.app.usage { field public static final String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService"; } + public class NetworkStatsManager { + method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.net.netstats.provider.NetworkStatsProviderCallback registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.AbstractNetworkStatsProvider); + } + public static final class UsageEvents.Event { method public int getInstanceId(); method @Nullable public String getNotificationChannelId(); @@ -1411,12 +1421,33 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); } - public final class BluetoothPan implements android.bluetooth.BluetoothProfile { - method protected void finalize(); + public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile { + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); + } + + public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile { method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice); method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice); - method public boolean isTetheringOn(); - method public void setBluetoothTethering(boolean); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int); + field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"; + } + + public final class BluetoothMap implements android.bluetooth.BluetoothProfile { + method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int); + field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED"; + } + + public final class BluetoothPan implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile { + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public void close(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) protected void finalize(); + method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isTetheringOn(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void setBluetoothTethering(boolean); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED"; field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE"; field public static final int LOCAL_NAP_ROLE = 1; // 0x1 @@ -1428,14 +1459,19 @@ package android.bluetooth { public class BluetoothPbap implements android.bluetooth.BluetoothProfile { method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED"; } public interface BluetoothProfile { + field public static final int A2DP_SINK = 11; // 0xb + field public static final int AVRCP_CONTROLLER = 12; // 0xc field public static final int CONNECTION_POLICY_ALLOWED = 100; // 0x64 field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0 field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff + field public static final int HEADSET_CLIENT = 16; // 0x10 field public static final int PAN = 5; // 0x5 + field public static final int PBAP_CLIENT = 17; // 0x11 field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0 field @Deprecated public static final int PRIORITY_ON = 100; // 0x64 } @@ -1543,7 +1579,9 @@ package android.content { field public static final String EUICC_CARD_SERVICE = "euicc_card"; field public static final String HDMI_CONTROL_SERVICE = "hdmi_control"; field public static final String NETD_SERVICE = "netd"; + field public static final String NETWORK_POLICY_SERVICE = "netpolicy"; field public static final String NETWORK_SCORE_SERVICE = "network_score"; + field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String OEM_LOCK_SERVICE = "oem_lock"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block"; @@ -1620,6 +1658,7 @@ package android.content { field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME"; field public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME"; field public static final String EXTRA_REASON = "android.intent.extra.REASON"; + field @Deprecated public static final String EXTRA_REBROADCAST_ON_UNLOCK = "rebroadcastOnUnlock"; field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK"; field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED"; field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME"; @@ -2054,6 +2093,15 @@ package android.content.rollback { } +package android.debug { + + public class AdbManager { + method @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public boolean isAdbWifiQrSupported(); + method @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public boolean isAdbWifiSupported(); + } + +} + package android.hardware { public final class Sensor { @@ -3229,9 +3277,17 @@ package android.hardware.usb { } public class UsbManager { + method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public long getCurrentFunctions(); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USB) public java.util.List<android.hardware.usb.UsbPort> getPorts(); method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void grantPermission(android.hardware.usb.UsbDevice, String); + method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long); field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED"; + field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE"; + field public static final long FUNCTION_NONE = 0L; // 0x0L + field public static final long FUNCTION_RNDIS = 32L; // 0x20L + field public static final String USB_CONFIGURED = "configured"; + field public static final String USB_CONNECTED = "connected"; + field public static final String USB_FUNCTION_RNDIS = "rndis"; } public final class UsbPort { @@ -3665,6 +3721,19 @@ package android.media { method public android.media.AudioAttributes.Builder setInternalCapturePreset(int); } + public final class AudioDeviceAddress implements android.os.Parcelable { + ctor public AudioDeviceAddress(@NonNull android.media.AudioDeviceInfo); + ctor public AudioDeviceAddress(int, int, @NonNull String); + method public int describeContents(); + method @NonNull public String getAddress(); + method public int getRole(); + method public int getType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioDeviceAddress> CREATOR; + field public static final int ROLE_INPUT = 1; // 0x1 + field public static final int ROLE_OUTPUT = 2; // 0x2 + } + public final class AudioFocusInfo implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.media.AudioAttributes getAttributes(); @@ -3786,6 +3855,14 @@ package android.media { } +package android.media.audiofx { + + public class AudioEffect { + ctor @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public AudioEffect(@NonNull java.util.UUID, @NonNull android.media.AudioDeviceAddress); + } + +} + package android.media.audiopolicy { public class AudioMix { @@ -3972,6 +4049,15 @@ package android.media.soundtrigger { package android.media.tv { + public final class DvbDeviceInfo implements android.os.Parcelable { + ctor public DvbDeviceInfo(int, int); + method public int describeContents(); + method public int getAdapterId(); + method public int getDeviceId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR; + } + public final class TvContentRatingSystemInfo implements android.os.Parcelable { method public static android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo); method public int describeContents(); @@ -4086,12 +4172,14 @@ package android.media.tv { method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating); method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig); method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String); + method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList(); method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList(); method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList(); method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean isSingleSessionActive(); method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyPreviewProgramAddedToWatchNext(String, long, long); method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyPreviewProgramBrowsableDisabled(String, long); method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyWatchNextProgramBrowsableDisabled(String, long); + method @Nullable @RequiresPermission("android.permission.DVB_DEVICE") public android.os.ParcelFileDescriptor openDvbDevice(@NonNull android.media.tv.DvbDeviceInfo, int); method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public void releaseTvInputHardware(int, android.media.tv.TvInputManager.Hardware); method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void removeBlockedRating(@NonNull android.media.tv.TvContentRating); method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void setParentalControlsEnabled(boolean); @@ -4212,25 +4300,56 @@ package android.net { public class CaptivePortal implements android.os.Parcelable { method public void logEvent(int, @NonNull String); + method public void reevaluateNetwork(); method public void useNetwork(); + field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64 field public static final int APP_RETURN_DISMISSED = 0; // 0x0 field public static final int APP_RETURN_UNWANTED = 1; // 0x1 field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2 } + public final class CaptivePortalData implements android.os.Parcelable { + method public int describeContents(); + method public long getByteLimit(); + method public long getExpiryTimeMillis(); + method public long getRefreshTimeMillis(); + method @Nullable public android.net.Uri getUserPortalUrl(); + method @Nullable public android.net.Uri getVenueInfoUrl(); + method public boolean isCaptive(); + method public boolean isSessionExtendable(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR; + } + + public static class CaptivePortalData.Builder { + ctor public CaptivePortalData.Builder(); + ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData); + method @NonNull public android.net.CaptivePortalData build(); + method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long); + method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean); + method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long); + method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long); + method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean); + method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri); + method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri); + } + public class ConnectivityManager { method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); method @Deprecated @RequiresPermission("android.permission.NETWORK_SETTINGS") public String getCaptivePortalServerUrl(); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported(); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public int registerNetworkProvider(@NonNull android.net.NetworkProvider); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback); + method @Deprecated public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int, int, @NonNull android.os.Handler); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "android.permission.NETWORK_STACK"}) public boolean shouldAvoidBadWifi(); method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback); field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; @@ -4240,6 +4359,8 @@ package android.net { field public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TYPE_NONE = -1; // 0xffffffff + field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd } public abstract static class ConnectivityManager.OnStartTetheringCallback { @@ -4257,6 +4378,14 @@ package android.net { method public void onUpstreamChanged(@Nullable android.net.Network); } + public class InvalidPacketException extends java.lang.Exception { + ctor public InvalidPacketException(int); + field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb + field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9 + field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea + field public final int error; + } + public final class IpConfiguration implements android.os.Parcelable { ctor public IpConfiguration(); ctor public IpConfiguration(@NonNull android.net.IpConfiguration); @@ -4307,6 +4436,15 @@ package android.net { method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; } + public class KeepalivePacketData { + ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException; + method @NonNull public byte[] getPacket(); + field @NonNull public final java.net.InetAddress dstAddress; + field public final int dstPort; + field @NonNull public final java.net.InetAddress srcAddress; + field public final int srcPort; + } + public class LinkAddress implements android.os.Parcelable { ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int); ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int); @@ -4327,6 +4465,8 @@ package android.net { method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames(); method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses(); method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes(); + method @Nullable public android.net.Uri getCaptivePortalApiUrl(); + method @Nullable public android.net.CaptivePortalData getCaptivePortalData(); method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers(); method @Nullable public String getTcpBufferSizes(); method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers(); @@ -4340,9 +4480,12 @@ package android.net { method public boolean isIpv6Provisioned(); method public boolean isProvisioned(); method public boolean isReachable(@NonNull java.net.InetAddress); + method @NonNull public android.net.LinkProperties makeSensitiveFieldsParcelingCopy(); method public boolean removeDnsServer(@NonNull java.net.InetAddress); method public boolean removeLinkAddress(@NonNull android.net.LinkAddress); method public boolean removeRoute(@NonNull android.net.RouteInfo); + method public void setCaptivePortalApiUrl(@Nullable android.net.Uri); + method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData); method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>); method public void setPrivateDnsServerName(@Nullable String); method public void setTcpBufferSizes(@Nullable String); @@ -4353,17 +4496,44 @@ package android.net { public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { ctor public MatchAllNetworkSpecifier(); method public int describeContents(); + method public boolean satisfiedBy(android.net.NetworkSpecifier); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.MatchAllNetworkSpecifier> CREATOR; } + public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable { + ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException; + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR; + } + public class Network implements android.os.Parcelable { ctor public Network(@NonNull android.net.Network); method @NonNull public android.net.Network getPrivateDnsBypassingCopy(); field public final int netId; } + public final class NetworkAgentConfig implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public String getSubscriberId(); + method public boolean isNat64DetectionEnabled(); + method public boolean isProvisioningNotificationEnabled(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR; + } + + public static class NetworkAgentConfig.Builder { + ctor public NetworkAgentConfig.Builder(); + method @NonNull public android.net.NetworkAgentConfig build(); + method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection(); + method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification(); + method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String); + } + public final class NetworkCapabilities implements android.os.Parcelable { + method public boolean deduceRestrictedCapability(); + method @Nullable public String getSSID(); method @NonNull public int[] getTransportTypes(); method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities); method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String); @@ -4383,12 +4553,27 @@ package android.net { field public final android.net.WifiKey wifiKey; } + public class NetworkProvider { + ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest); + method @Nullable public android.os.Messenger getMessenger(); + method @NonNull public String getName(); + method public int getProviderId(); + method public void onNetworkRequested(@NonNull android.net.NetworkRequest, int, int); + method public void onRequestWithdrawn(@NonNull android.net.NetworkRequest); + field public static final int ID_NONE = -1; // 0xffffffff + } + public abstract class NetworkRecommendationProvider { ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor); method public final android.os.IBinder getBinder(); method public abstract void onRequestScores(android.net.NetworkKey[]); } + public class NetworkRequest implements android.os.Parcelable { + method public boolean satisfiedBy(@Nullable android.net.NetworkCapabilities); + } + public static class NetworkRequest.Builder { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int); } @@ -4409,6 +4594,9 @@ package android.net { field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore"; field public static final String EXTRA_NEW_SCORER = "newScorer"; field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName"; + field public static final int SCORE_FILTER_CURRENT_NETWORK = 1; // 0x1 + field public static final int SCORE_FILTER_NONE = 0; // 0x0 + field public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2 } public static interface NetworkScoreManager.NetworkScoreCallback { @@ -4416,10 +4604,43 @@ package android.net { method public void updateScores(@NonNull java.util.List<android.net.ScoredNetwork>); } + public abstract class NetworkSpecifier { + method public void assertValidFromUid(int); + method @Nullable public android.net.NetworkSpecifier redact(); + method public abstract boolean satisfiedBy(@Nullable android.net.NetworkSpecifier); + } + public class NetworkStack { field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK"; } + public final class NetworkStats implements android.os.Parcelable { + ctor public NetworkStats(long, int); + method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats); + method @NonNull public android.net.NetworkStats addValues(@NonNull android.net.NetworkStats.Entry); + method public int describeContents(); + method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR; + field public static final int DEFAULT_NETWORK_NO = 0; // 0x0 + field public static final int DEFAULT_NETWORK_YES = 1; // 0x1 + field @Nullable public static final String IFACE_ALL; + field public static final String IFACE_VT = "vt_data0"; + field public static final int METERED_NO = 0; // 0x0 + field public static final int METERED_YES = 1; // 0x1 + field public static final int ROAMING_NO = 0; // 0x0 + field public static final int ROAMING_YES = 1; // 0x1 + field public static final int SET_DEFAULT = 0; // 0x0 + field public static final int SET_FOREGROUND = 1; // 0x1 + field public static final int TAG_NONE = 0; // 0x0 + field public static final int UID_ALL = -1; // 0xffffffff + field public static final int UID_TETHERING = -5; // 0xfffffffb + } + + public static class NetworkStats.Entry { + ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long); + } + public final class RouteInfo implements android.os.Parcelable { ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int); method public int getType(); @@ -4459,6 +4680,10 @@ package android.net { field public final android.net.RssiCurve rssiCurve; } + public abstract class SocketKeepalive implements java.lang.AutoCloseable { + field public static final int SUCCESS = 0; // 0x0 + } + public final class StaticIpConfiguration implements android.os.Parcelable { ctor public StaticIpConfiguration(); ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration); @@ -4486,11 +4711,16 @@ package android.net { public final class StringNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { ctor public StringNetworkSpecifier(@NonNull String); method public int describeContents(); + method public boolean satisfiedBy(android.net.NetworkSpecifier); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.StringNetworkSpecifier> CREATOR; field @NonNull public final String specifier; } + public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + method public boolean satisfiedBy(android.net.NetworkSpecifier); + } + public class TrafficStats { method public static void setThreadStatsTagApp(); method public static void setThreadStatsTagBackup(); @@ -4616,9 +4846,11 @@ package android.net.ipsec.ike { } public abstract class ChildSessionParams { + method public long getHardLifetime(); method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors(); method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors(); method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals(); + method public long getSoftLifetime(); } public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification { @@ -4687,12 +4919,14 @@ package android.net.ipsec.ike { } public final class IkeSessionParams { + method public long getHardLifetime(); method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig(); method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification(); method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig(); method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification(); method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals(); method @NonNull public java.net.InetAddress getServerAddress(); + method public long getSoftLifetime(); method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket(); } @@ -4704,6 +4938,7 @@ package android.net.ipsec.ike { method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@Nullable java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]); + method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLifetime(long, long); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress); @@ -4774,6 +5009,7 @@ package android.net.ipsec.ike { method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal); method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build(); + method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder setLifetime(long, long); } public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams { @@ -4791,6 +5027,7 @@ package android.net.ipsec.ike { method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal); method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build(); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder setLifetime(long, long); } public static interface TunnelModeChildSessionParams.ConfigRequest { @@ -5010,6 +5247,25 @@ package android.net.metrics { } +package android.net.netstats.provider { + + public abstract class AbstractNetworkStatsProvider { + ctor public AbstractNetworkStatsProvider(); + method public abstract void requestStatsUpdate(int); + method public abstract void setAlert(long); + method public abstract void setLimit(@NonNull String, long); + field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff + } + + public class NetworkStatsProviderCallback { + method public void onAlertReached(); + method public void onLimitReached(); + method public void onStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats); + method public void unregister(); + } + +} + package android.net.util { public final class SocketUtils { @@ -5359,6 +5615,10 @@ package android.net.wifi { field public int numUsage; } + public final class WifiNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + method public boolean satisfiedBy(android.net.NetworkSpecifier); + } + public class WifiScanner { method @Deprecated public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]); method @Deprecated public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings); @@ -5523,6 +5783,10 @@ package android.net.wifi.aware { method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]); } + public final class WifiAwareNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + method public boolean satisfiedBy(android.net.NetworkSpecifier); + } + public static final class WifiAwareNetworkSpecifier.Builder { method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPmk(@NonNull byte[]); } @@ -6099,11 +6363,13 @@ package android.os { public class UpdateEngine { ctor public UpdateEngine(); + method @NonNull public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]); method public void applyPayload(String, long, long, String[]); - method public void applyPayload(@NonNull android.os.ParcelFileDescriptor, long, long, @NonNull String[]); + method public void applyPayload(@NonNull android.content.res.AssetFileDescriptor, @NonNull String[]); method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler); method public boolean bind(android.os.UpdateEngineCallback); method public void cancel(); + method public int cleanupAppliedPayload(); method public void resetStatus(); method public void resume(); method public void suspend(); @@ -6111,14 +6377,21 @@ package android.os { method public boolean verifyPayloadMetadata(String); } + public static final class UpdateEngine.AllocateSpaceResult { + method public int errorCode(); + method public long freeSpaceRequired(); + } + public static final class UpdateEngine.ErrorCodeConstants { ctor public UpdateEngine.ErrorCodeConstants(); + field public static final int DEVICE_CORRUPTED = 61; // 0x3d field public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; // 0xc field public static final int DOWNLOAD_TRANSFER_ERROR = 9; // 0x9 field public static final int ERROR = 1; // 0x1 field public static final int FILESYSTEM_COPIER_ERROR = 4; // 0x4 field public static final int INSTALL_DEVICE_OPEN_ERROR = 7; // 0x7 field public static final int KERNEL_DEVICE_OPEN_ERROR = 8; // 0x8 + field public static final int NOT_ENOUGH_SPACE = 60; // 0x3c field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6 field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb @@ -6638,6 +6911,7 @@ package android.provider { } public final class Settings { + method public static boolean checkAndNoteWriteSettingsOperation(@NonNull android.content.Context, int, @NonNull String, boolean); field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS"; field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS"; field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS"; @@ -6646,6 +6920,7 @@ package android.provider { field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS"; field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE"; field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"; + field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI"; } public static final class Settings.Global extends android.provider.Settings.NameValueTable { @@ -6663,6 +6938,7 @@ package android.provider { field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis"; field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; field public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt"; + field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"; field public static final String TETHER_SUPPORTED = "tether_supported"; field public static final String THEATER_MODE_ON = "theater_mode_on"; field public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess"; @@ -6735,7 +7011,9 @@ package android.provider { public static final class Telephony.Carriers implements android.provider.BaseColumns { field public static final String APN_SET_ID = "apn_set_id"; field public static final int CARRIER_EDITED = 4; // 0x4 + field @NonNull public static final android.net.Uri DPC_URI; field public static final String EDITED_STATUS = "edited"; + field public static final int INVALID_APN_ID = -1; // 0xffffffff field public static final String MAX_CONNECTIONS = "max_conns"; field public static final String MODEM_PERSIST = "modem_cognitive"; field public static final String MTU = "mtu"; @@ -6750,6 +7028,9 @@ package android.provider { } public static final class Telephony.CellBroadcasts implements android.provider.BaseColumns { + field @NonNull public static final String AUTHORITY_LEGACY = "cellbroadcast-legacy"; + field @NonNull public static final android.net.Uri AUTHORITY_LEGACY_URI; + field @NonNull public static final String CALL_METHOD_GET_PREFERENCE = "get_preference"; field public static final String CID = "cid"; field public static final String CMAS_CATEGORY = "cmas_category"; field public static final String CMAS_CERTAINTY = "cmas_certainty"; @@ -6780,6 +7061,20 @@ package android.provider { field public static final String SUB_ID = "sub_id"; } + public static final class Telephony.CellBroadcasts.Preference { + field @NonNull public static final String ENABLE_ALERT_VIBRATION_PREF = "enable_alert_vibrate"; + field @NonNull public static final String ENABLE_AREA_UPDATE_INFO_PREF = "enable_area_update_info_alerts"; + field @NonNull public static final String ENABLE_CMAS_AMBER_PREF = "enable_cmas_amber_alerts"; + field @NonNull public static final String ENABLE_CMAS_EXTREME_THREAT_PREF = "enable_cmas_extreme_threat_alerts"; + field @NonNull public static final String ENABLE_CMAS_IN_SECOND_LANGUAGE_PREF = "receive_cmas_in_second_language"; + field @NonNull public static final String ENABLE_CMAS_PRESIDENTIAL_PREF = "enable_cmas_presidential_alerts"; + field @NonNull public static final String ENABLE_CMAS_SEVERE_THREAT_PREF = "enable_cmas_severe_threat_alerts"; + field @NonNull public static final String ENABLE_EMERGENCY_PERF = "enable_emergency_alerts"; + field @NonNull public static final String ENABLE_PUBLIC_SAFETY_PREF = "enable_public_safety_messages"; + field @NonNull public static final String ENABLE_STATE_LOCAL_TEST_PREF = "enable_state_local_test_alerts"; + field @NonNull public static final String ENABLE_TEST_ALERT_PREF = "enable_test_alerts"; + } + public static final class Telephony.SimInfo { field @NonNull public static final android.net.Uri CONTENT_URI; } @@ -7894,8 +8189,6 @@ package android.telephony { public final class AccessNetworkConstants { field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff - field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2 - field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1 } public final class CallAttributes implements android.os.Parcelable { @@ -8007,6 +8300,41 @@ package android.telephony { field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService"; } + public abstract class CellIdentity implements android.os.Parcelable { + method @NonNull public abstract android.telephony.CellLocation asCellLocation(); + method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo(); + } + + public final class CellIdentityCdma extends android.telephony.CellIdentity { + method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation(); + method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo(); + } + + public final class CellIdentityGsm extends android.telephony.CellIdentity { + method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation(); + method @NonNull public android.telephony.CellIdentityGsm sanitizeLocationInfo(); + } + + public final class CellIdentityLte extends android.telephony.CellIdentity { + method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation(); + method @NonNull public android.telephony.CellIdentityLte sanitizeLocationInfo(); + } + + public final class CellIdentityNr extends android.telephony.CellIdentity { + method @NonNull public android.telephony.CellLocation asCellLocation(); + method @NonNull public android.telephony.CellIdentityNr sanitizeLocationInfo(); + } + + public final class CellIdentityTdscdma extends android.telephony.CellIdentity { + method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation(); + method @NonNull public android.telephony.CellIdentityTdscdma sanitizeLocationInfo(); + } + + public final class CellIdentityWcdma extends android.telephony.CellIdentity { + method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation(); + method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo(); + } + public final class DataFailCause { field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab field public static final int ACCESS_BLOCK = 2087; // 0x827 @@ -8488,35 +8816,18 @@ package android.telephony { } public final class NetworkRegistrationInfo implements android.os.Parcelable { - method public int describeContents(); - method public int getAccessNetworkTechnology(); - method @NonNull public java.util.List<java.lang.Integer> getAvailableServices(); - method @Nullable public android.telephony.CellIdentity getCellIdentity(); method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo(); - method public int getDomain(); - method public int getNrState(); method public int getRegistrationState(); method public int getRejectCause(); method public int getRoamingType(); - method public int getTransportType(); method public boolean isEmergencyEnabled(); - method public boolean isRoaming(); method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR; - field public static final int DOMAIN_CS = 1; // 0x1 - field public static final int DOMAIN_PS = 2; // 0x2 field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3 field public static final int REGISTRATION_STATE_HOME = 1; // 0x1 field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0 field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2 field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5 field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4 - field public static final int SERVICE_TYPE_DATA = 2; // 0x2 - field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 - field public static final int SERVICE_TYPE_SMS = 3; // 0x3 - field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0 - field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 - field public static final int SERVICE_TYPE_VOICE = 1; // 0x1 } public static final class NetworkRegistrationInfo.Builder { @@ -8591,7 +8902,7 @@ package android.telephony { method public void onRadioPowerStateChanged(int); method public void onSrvccStateChanged(int); method public void onVoiceActivationStateChanged(int); - field public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000 + field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000 field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000 field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000 field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800 @@ -8621,6 +8932,7 @@ package android.telephony { } public final class PreciseDataConnectionState implements android.os.Parcelable { + ctor public PreciseDataConnectionState(int, int, int, @NonNull String, @Nullable android.net.LinkProperties, int, @Nullable android.telephony.data.ApnSetting); method @Deprecated @NonNull public String getDataConnectionApn(); method @Deprecated public int getDataConnectionApnTypeBitMask(); method @Deprecated public int getDataConnectionFailCause(); @@ -8727,19 +9039,27 @@ package android.telephony { } public class ServiceState implements android.os.Parcelable { + method @NonNull public android.telephony.ServiceState createLocationInfoSanitizedCopy(boolean); + method public void fillInNotifierBundle(@NonNull android.os.Bundle); + method public int getDataNetworkType(); + method public int getDataRegistrationState(); method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int); - method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList(); method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int); method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int); method public int getNrFrequencyRange(); method @Nullable public String getOperatorAlphaLongRaw(); method @Nullable public String getOperatorAlphaShortRaw(); + method @NonNull public static android.telephony.ServiceState newFromBundle(@NonNull android.os.Bundle); field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2 field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3 field public static final int ROAMING_TYPE_NOT_ROAMING = 0; // 0x0 field public static final int ROAMING_TYPE_UNKNOWN = 1; // 0x1 } + public class SignalStrength implements android.os.Parcelable { + ctor public SignalStrength(@NonNull android.telephony.SignalStrength); + } + public final class SmsCbCmasInfo implements android.os.Parcelable { ctor public SmsCbCmasInfo(int, int, int, int, int, int); method public int describeContents(); @@ -8863,13 +9183,22 @@ package android.telephony { } public final class SmsManager { + method @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public boolean copyMessageToIcc(@Nullable byte[], @NonNull byte[], int); + method @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public boolean deleteMessageFromIcc(int); method public boolean disableCellBroadcastRange(int, int, int); method public boolean enableCellBroadcastRange(int, int, int); + method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public java.util.List<android.telephony.SmsMessage> getMessagesFromIcc(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSmsCapacityOnIcc(); method public void sendMultipartTextMessage(@NonNull String, @NonNull String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, @NonNull String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>); } + public class SmsMessage { + method @Nullable public static android.telephony.SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[], boolean); + method @Nullable public static android.telephony.SmsMessage.SubmitPdu getSmsPdu(int, int, @Nullable String, @NonNull String, @NonNull String, long); + method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, int, int, int, int, int); + } + public class SubscriptionInfo implements android.os.Parcelable { method public boolean areUiccApplicationsEnabled(); method @Nullable public java.util.List<android.telephony.UiccAccessRule> getAccessRules(); @@ -8879,6 +9208,8 @@ package android.telephony { public class SubscriptionManager { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean canDisablePhysicalSubscription(); + method public boolean canManageSubscription(@Nullable android.telephony.SubscriptionInfo, @Nullable String); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String); method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int); method @NonNull public static android.content.res.Resources getResourcesForSubId(@NonNull android.content.Context, int); @@ -8890,6 +9221,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultVoiceSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUiccApplicationsEnabled(boolean, int); field @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS) public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED"; field @NonNull public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI; field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff @@ -8931,6 +9263,7 @@ package android.telephony { } public class TelephonyManager { + method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting); method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); method public int checkCarrierPrivilegesForPackage(String); method public int checkCarrierPrivilegesForPackageAnyPhone(String); @@ -8944,6 +9277,7 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); @@ -8957,10 +9291,12 @@ package android.telephony { method @Deprecated public boolean getDataEnabled(); method @Deprecated public boolean getDataEnabled(int); method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean); + method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode(); method public int getEmergencyNumberDbVersion(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getIsimImpu(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping(); method public int getMaxNumberOfSimultaneouslyActiveSims(); @@ -8980,26 +9316,29 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int); + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int); method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String); - method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String); + method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String); + method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int); + method public boolean isCurrentSimOperator(@NonNull String, int, @Nullable String); method public boolean isDataConnectivityPossible(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isManualNetworkSelectionAllowed(); method public boolean isModemEnabledForSlot(int); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetheringApnRequired(); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isTetheringApnRequired(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); + method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); method public boolean needsOtaServiceProvisioning(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); @@ -9037,10 +9376,12 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String); field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED"; field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE"; - field public static final String ACTION_NETWORK_SET_TIME = "android.telephony.action.NETWORK_SET_TIME"; field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; + field public static final int CARD_POWER_DOWN = 0; // 0x0 + field public static final int CARD_POWER_UP = 1; // 0x1 + field public static final int CARD_POWER_UP_PASS_THROUGH = 2; // 0x2 field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 @@ -9073,6 +9414,7 @@ package android.telephony { field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L + field public static final int PHONE_TYPE_THIRD_PARTY = 4; // 0x4 field public static final int RADIO_POWER_OFF = 0; // 0x0 field public static final int RADIO_POWER_ON = 1; // 0x1 field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2 @@ -9098,6 +9440,7 @@ package android.telephony { method public void addOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyCallStateChangedForAllSubscriptions(int, @Nullable String); method public void notifyCarrierNetworkChange(boolean); + method public void notifyRegistrationFailed(int, int, @NonNull android.telephony.CellIdentity, @NonNull String, int, int, int); method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void removeOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); } @@ -9473,6 +9816,7 @@ package android.telephony.ims { method public int getEmergencyServiceCategories(); method @NonNull public java.util.List<java.lang.String> getEmergencyUrns(); method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile(); + method @Nullable public android.os.Bundle getProprietaryCallExtras(); method public int getRestrictCause(); method public int getServiceType(); method public static int getVideoStateFromCallType(int); @@ -9516,7 +9860,8 @@ package android.telephony.ims { field public static final int DIALSTRING_USSD = 2; // 0x2 field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo"; field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS"; - field public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech"; + field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE"; + field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech"; field public static final String EXTRA_CHILD_NUMBER = "ChildNum"; field public static final String EXTRA_CNA = "cna"; field public static final String EXTRA_CNAP = "cnap"; @@ -9548,8 +9893,8 @@ package android.telephony.ims { method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState); - method public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo); - method public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo); + method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo); + method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo); method public void callSessionHeld(android.telephony.ims.ImsCallProfile); method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile); @@ -9557,7 +9902,7 @@ package android.telephony.ims { method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionInviteParticipantsRequestDelivered(); method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionMayHandover(int, int); + method @Deprecated public void callSessionMayHandover(int, int); method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase); method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); @@ -9579,6 +9924,9 @@ package android.telephony.ims { method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile); method public void callSessionUpdated(android.telephony.ims.ImsCallProfile); method public void callSessionUssdMessageReceived(int, String); + method public void onHandover(int, int, @Nullable android.telephony.ims.ImsReasonInfo); + method public void onHandoverFailed(int, int, @NonNull android.telephony.ims.ImsReasonInfo); + method public void onMayHandover(int, int); } public final class ImsConferenceState implements android.os.Parcelable { @@ -9610,10 +9958,6 @@ package android.telephony.ims { ctor public ImsException(@Nullable String); ctor public ImsException(@Nullable String, int); ctor public ImsException(@Nullable String, int, @Nullable Throwable); - method public int getCode(); - field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1 - field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0 - field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2 } public final class ImsExternalCallState implements android.os.Parcelable { @@ -9635,26 +9979,20 @@ package android.telephony.ims { public class ImsManager { method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int); + field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION"; + field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; + field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; + field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTtyOverVolteEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int); @@ -9664,16 +10002,6 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback); - field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1 - field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0 - field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2 - } - - public static class ImsMmTelManager.CapabilityCallback { - ctor public ImsMmTelManager.CapabilityCallback(); - method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities); } @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback { @@ -9929,17 +10257,90 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); + field public static final int KEY_1X_EPDG_TIMER_SEC = 64; // 0x40 + field public static final int KEY_1X_THRESHOLD = 59; // 0x3b + field public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50; // 0x32 + field public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0; // 0x0 + field public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53; // 0x35 + field public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49; // 0x31 + field public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48; // 0x30 + field public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1; // 0x1 + field public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47; // 0x2f + field public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52; // 0x34 + field public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51; // 0x33 + field public static final int KEY_EAB_PROVISIONING_STATUS = 25; // 0x19 + field public static final int KEY_ENABLE_SILENT_REDIAL = 6; // 0x6 + field public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31; // 0x1f + field public static final int KEY_LTE_EPDG_TIMER_SEC = 62; // 0x3e + field public static final int KEY_LTE_THRESHOLD_1 = 56; // 0x38 + field public static final int KEY_LTE_THRESHOLD_2 = 57; // 0x39 + field public static final int KEY_LTE_THRESHOLD_3 = 58; // 0x3a + field public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3; // 0x3 + field public static final int KEY_MOBILE_DATA_ENABLED = 29; // 0x1d + field public static final int KEY_MULTIENDPOINT_ENABLED = 65; // 0x41 + field public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; // 0x13 + field public static final int KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC = 18; // 0x12 + field public static final int KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC = 20; // 0x14 + field public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17; // 0x11 + field public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23; // 0x17 + field public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22; // 0x16 + field public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; // 0x15 + field public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; // 0x10 + field public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; // 0xf + field public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; // 0xc + field public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; // 0x21 + field public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34; // 0x22 + field public static final int KEY_RTP_SPEECH_END_PORT = 36; // 0x24 + field public static final int KEY_RTP_SPEECH_START_PORT = 35; // 0x23 + field public static final int KEY_RTT_ENABLED = 66; // 0x42 + field public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43; // 0x2b + field public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44; // 0x2c + field public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38; // 0x26 + field public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4; // 0x4 + field public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37; // 0x25 + field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42; // 0x2a + field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39; // 0x27 + field public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32; // 0x20 + field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45; // 0x2d + field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40; // 0x28 + field public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46; // 0x2e + field public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41; // 0x29 + field public static final int KEY_SIP_SESSION_TIMER_SEC = 2; // 0x2 + field public static final int KEY_SMS_FORMAT = 13; // 0xd + field public static final int KEY_SMS_OVER_IP_ENABLED = 14; // 0xe + field public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54; // 0x36 + field public static final int KEY_T1_TIMER_VALUE_MS = 7; // 0x7 + field public static final int KEY_T2_TIMER_VALUE_MS = 8; // 0x8 + field public static final int KEY_TF_TIMER_VALUE_MS = 9; // 0x9 + field public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5; // 0x5 + field public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24; // 0x18 + field public static final int KEY_VIDEO_QUALITY = 55; // 0x37 + field public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28; // 0x1c field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a + field public static final int KEY_VOLTE_PROVISIONING_STATUS = 10; // 0xa + field public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30; // 0x1e + field public static final int KEY_VT_PROVISIONING_STATUS = 11; // 0xb + field public static final int KEY_WIFI_EPDG_TIMER_SEC = 63; // 0x3f + field public static final int KEY_WIFI_THRESHOLD_A = 60; // 0x3c + field public static final int KEY_WIFI_THRESHOLD_B = 61; // 0x3d + field public static final int PROVISIONING_RESULT_UNKNOWN = -1; // 0xffffffff field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0 field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1 + field public static final int SMS_FORMAT_3GPP = 1; // 0x1 + field public static final int SMS_FORMAT_3GPP2 = 0; // 0x0 field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC"; field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY"; + field public static final int VIDEO_QUALITY_HIGH = 1; // 0x1 + field public static final int VIDEO_QUALITY_LOW = 0; // 0x0 } public static class ProvisioningManager.Callback { @@ -9948,22 +10349,52 @@ package android.telephony.ims { method public void onProvisioningStringChanged(int, @NonNull String); } - public interface RegistrationManager { - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); - field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0 - field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2 - field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1 - } - - public static class RegistrationManager.RegistrationCallback { - ctor public RegistrationManager.RegistrationCallback(); - method public void onRegistered(int); - method public void onRegistering(int); - method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo); - method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo); + public final class RcsContactUceCapability implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags(); + method @NonNull public android.net.Uri getContactUri(); + method @Nullable public android.net.Uri getServiceUri(int); + method public boolean isCapable(int); + method public boolean isCapable(@NonNull String); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000 + field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000 + field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000 + field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2 + field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4 + field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1 + field public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = 4096; // 0x1000 + field public static final int CAPABILITY_FILE_TRANSFER = 8; // 0x8 + field public static final int CAPABILITY_FILE_TRANSFER_HTTP = 64; // 0x40 + field public static final int CAPABILITY_FILE_TRANSFER_SMS = 128; // 0x80 + field public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = 32; // 0x20 + field public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = 16; // 0x10 + field public static final int CAPABILITY_GEOLOCATION_PULL = 131072; // 0x20000 + field public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = 262144; // 0x40000 + field public static final int CAPABILITY_GEOLOCATION_PUSH = 32768; // 0x8000 + field public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = 65536; // 0x10000 + field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100 + field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000 + field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000 + field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000 + field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000 + field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000 + field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000 + field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000 + field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000 + field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000 + field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800 + field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400 + field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200 + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR; + } + + public static class RcsContactUceCapability.Builder { + ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int, @NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String); + method @NonNull public android.telephony.ims.RcsContactUceCapability build(); } } @@ -9989,6 +10420,7 @@ package android.telephony.ims.feature { public abstract class ImsFeature { ctor public ImsFeature(); method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method public int getFeatureState(); method public final int getSlotIndex(); method public abstract void onFeatureReady(); method public abstract void onFeatureRemoved(); @@ -10027,7 +10459,7 @@ package android.telephony.ims.feature { method public void onFeatureReady(); method public void onFeatureRemoved(); method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); - method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); + method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); method public void setUiTtyMode(int, @Nullable android.os.Message); method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]); field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; @@ -10043,10 +10475,6 @@ package android.telephony.ims.feature { method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); - field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 - field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 - field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 - field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1 } @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability { @@ -10137,6 +10565,7 @@ package android.telephony.ims.stub { method public String getConfigString(int); method public final void notifyProvisionedValueChanged(int, int); method public final void notifyProvisionedValueChanged(int, String); + method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method public int setConfig(int, int); method public int setConfig(int, String); field public static final int CONFIG_RESULT_FAILED = 1; // 0x1 @@ -10235,6 +10664,17 @@ package android.telephony.ims.stub { method public int updateClir(int); method public int updateColp(boolean); method public int updateColr(int); + field public static final int CALL_BARRING_ALL = 7; // 0x7 + field public static final int CALL_BARRING_ALL_INCOMING = 1; // 0x1 + field public static final int CALL_BARRING_ALL_OUTGOING = 2; // 0x2 + field public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; // 0x6 + field public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; // 0x9 + field public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; // 0x8 + field public static final int CALL_BARRING_OUTGOING_INTL = 3; // 0x3 + field public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; // 0x4 + field public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; // 0xa + field public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; // 0x5 + field public static final int INVALID_RESULT = -1; // 0xffffffff } } diff --git a/api/test-current.txt b/api/test-current.txt index 68da72f2204c..b5915d50f5e4 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -320,8 +320,10 @@ package android.app { } public final class NotificationChannel implements android.os.Parcelable { + method public boolean isBlockableSystem(); method public boolean isImportanceLockedByCriticalDeviceFunction(); method public boolean isImportanceLockedByOEM(); + method public void setBlockableSystem(boolean); method public void setImportanceLockedByCriticalDeviceFunction(boolean); method public void setImportanceLockedByOEM(boolean); } @@ -352,6 +354,7 @@ package android.app { public class StatusBarManager { method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo(); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean); } public static final class StatusBarManager.DisableInfo { @@ -650,6 +653,7 @@ package android.content { method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions); field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; + field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String ROLLBACK_SERVICE = "rollback"; field public static final String STATUS_BAR_SERVICE = "statusbar"; @@ -1349,12 +1353,40 @@ package android.net { public class CaptivePortal implements android.os.Parcelable { method public void logEvent(int, @NonNull String); + method public void reevaluateNetwork(); method public void useNetwork(); + field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64 field public static final int APP_RETURN_DISMISSED = 0; // 0x0 field public static final int APP_RETURN_UNWANTED = 1; // 0x1 field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2 } + public final class CaptivePortalData implements android.os.Parcelable { + method public int describeContents(); + method public long getByteLimit(); + method public long getExpiryTimeMillis(); + method public long getRefreshTimeMillis(); + method @Nullable public android.net.Uri getUserPortalUrl(); + method @Nullable public android.net.Uri getVenueInfoUrl(); + method public boolean isCaptive(); + method public boolean isSessionExtendable(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR; + } + + public static class CaptivePortalData.Builder { + ctor public CaptivePortalData.Builder(); + ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData); + method @NonNull public android.net.CaptivePortalData build(); + method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long); + method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean); + method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long); + method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long); + method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean); + method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri); + method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri); + } + public class ConnectivityManager { method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle); field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; @@ -1385,6 +1417,8 @@ package android.net { ctor public LinkProperties(@Nullable android.net.LinkProperties); method public boolean addDnsServer(@NonNull java.net.InetAddress); method public boolean addLinkAddress(@NonNull android.net.LinkAddress); + method @Nullable public android.net.Uri getCaptivePortalApiUrl(); + method @Nullable public android.net.CaptivePortalData getCaptivePortalData(); method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers(); method @Nullable public String getTcpBufferSizes(); method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers(); @@ -1395,9 +1429,12 @@ package android.net { method public boolean isIpv6Provisioned(); method public boolean isProvisioned(); method public boolean isReachable(@NonNull java.net.InetAddress); + method @NonNull public android.net.LinkProperties makeSensitiveFieldsParcelingCopy(); method public boolean removeDnsServer(@NonNull java.net.InetAddress); method public boolean removeLinkAddress(@NonNull android.net.LinkAddress); method public boolean removeRoute(@NonNull android.net.RouteInfo); + method public void setCaptivePortalApiUrl(@Nullable android.net.Uri); + method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData); method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>); method public void setPrivateDnsServerName(@Nullable String); method public void setTcpBufferSizes(@Nullable String); @@ -2355,6 +2392,7 @@ package android.provider { public final class Settings { field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS"; field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE"; + field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI"; field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1 } @@ -2371,6 +2409,7 @@ package android.provider { field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky"; field public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices"; + field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"; field public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package"; } @@ -2884,8 +2923,6 @@ package android.telephony { public final class AccessNetworkConstants { field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff - field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2 - field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1 } public final class CallQuality implements android.os.Parcelable { @@ -2948,34 +2985,18 @@ package android.telephony { } public final class NetworkRegistrationInfo implements android.os.Parcelable { - method public int describeContents(); - method public int getAccessNetworkTechnology(); - method @NonNull public java.util.List<java.lang.Integer> getAvailableServices(); - method @Nullable public android.telephony.CellIdentity getCellIdentity(); method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo(); - method public int getDomain(); method public int getRegistrationState(); method public int getRejectCause(); method public int getRoamingType(); - method public int getTransportType(); method public boolean isEmergencyEnabled(); - method public boolean isRoaming(); method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR; - field public static final int DOMAIN_CS = 1; // 0x1 - field public static final int DOMAIN_PS = 2; // 0x2 field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3 field public static final int REGISTRATION_STATE_HOME = 1; // 0x1 field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0 field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2 field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5 field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4 - field public static final int SERVICE_TYPE_DATA = 2; // 0x2 - field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 - field public static final int SERVICE_TYPE_SMS = 3; // 0x3 - field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0 - field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 - field public static final int SERVICE_TYPE_VOICE = 1; // 0x1 } public static final class NetworkRegistrationInfo.Builder { @@ -3012,6 +3033,7 @@ package android.telephony { public class ServiceState implements android.os.Parcelable { method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo); + method public int getDataNetworkType(); method public void setCdmaSystemAndNetworkId(int, int); method public void setCellBandwidths(int[]); method public void setChannelNumber(int); @@ -3042,14 +3064,17 @@ package android.telephony { } public class TelephonyManager { + method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting); method public int checkCarrierPrivilegesForPackage(String); method public int getCarrierIdListVersion(); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean); + method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context); method public int getEmergencyNumberDbVersion(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNetworkCountryIso(int); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); + method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String); method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String); @@ -3117,6 +3142,7 @@ package android.telephony.ims { method public int getEmergencyServiceCategories(); method @NonNull public java.util.List<java.lang.String> getEmergencyUrns(); method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile(); + method @Nullable public android.os.Bundle getProprietaryCallExtras(); method public int getRestrictCause(); method public int getServiceType(); method public static int getVideoStateFromCallType(int); @@ -3160,7 +3186,8 @@ package android.telephony.ims { field public static final int DIALSTRING_USSD = 2; // 0x2 field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo"; field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS"; - field public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech"; + field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE"; + field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech"; field public static final String EXTRA_CHILD_NUMBER = "ChildNum"; field public static final String EXTRA_CNA = "cna"; field public static final String EXTRA_CNAP = "cnap"; @@ -3169,6 +3196,7 @@ package android.telephony.ims { field public static final String EXTRA_DISPLAY_TEXT = "DisplayText"; field public static final String EXTRA_EMERGENCY_CALL = "e_call"; field public static final String EXTRA_IS_CALL_PULL = "CallPull"; + field public static final String EXTRA_OEM_EXTRAS = "android.telephony.ims.extra.OEM_EXTRAS"; field public static final String EXTRA_OI = "oi"; field public static final String EXTRA_OIR = "oir"; field public static final String EXTRA_REMOTE_URI = "remote_uri"; @@ -3192,8 +3220,8 @@ package android.telephony.ims { method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState); - method public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo); - method public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo); + method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo); + method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo); method public void callSessionHeld(android.telephony.ims.ImsCallProfile); method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile); @@ -3201,7 +3229,7 @@ package android.telephony.ims { method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionInviteParticipantsRequestDelivered(); method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionMayHandover(int, int); + method @Deprecated public void callSessionMayHandover(int, int); method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase); method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); @@ -3223,6 +3251,9 @@ package android.telephony.ims { method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile); method public void callSessionUpdated(android.telephony.ims.ImsCallProfile); method public void callSessionUssdMessageReceived(int, String); + method public void onHandover(int, int, @Nullable android.telephony.ims.ImsReasonInfo); + method public void onHandoverFailed(int, int, @NonNull android.telephony.ims.ImsReasonInfo); + method public void onMayHandover(int, int); } public final class ImsConferenceState implements android.os.Parcelable { @@ -3254,10 +3285,6 @@ package android.telephony.ims { ctor public ImsException(@Nullable String); ctor public ImsException(@Nullable String, int); ctor public ImsException(@Nullable String, int, @Nullable Throwable); - method public int getCode(); - field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1 - field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0 - field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2 } public final class ImsExternalCallState implements android.os.Parcelable { @@ -3279,26 +3306,20 @@ package android.telephony.ims { public class ImsManager { method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int); + field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION"; + field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; + field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; + field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiModeSetting(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAdvancedCallingSettingEnabled(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isTtyOverVolteEnabled(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVoWiFiRoamingSettingEnabled(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVoWiFiSettingEnabled(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVtSettingEnabled(); method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int); @@ -3308,16 +3329,6 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean); method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback); - field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1 - field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0 - field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2 - } - - public static class ImsMmTelManager.CapabilityCallback { - ctor public ImsMmTelManager.CapabilityCallback(); - method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities); } @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback { @@ -3569,17 +3580,90 @@ package android.telephony.ims { method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public int getProvisioningIntValue(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public String getProvisioningStringValue(int); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); + field public static final int KEY_1X_EPDG_TIMER_SEC = 64; // 0x40 + field public static final int KEY_1X_THRESHOLD = 59; // 0x3b + field public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50; // 0x32 + field public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0; // 0x0 + field public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53; // 0x35 + field public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49; // 0x31 + field public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48; // 0x30 + field public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1; // 0x1 + field public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47; // 0x2f + field public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52; // 0x34 + field public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51; // 0x33 + field public static final int KEY_EAB_PROVISIONING_STATUS = 25; // 0x19 + field public static final int KEY_ENABLE_SILENT_REDIAL = 6; // 0x6 + field public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31; // 0x1f + field public static final int KEY_LTE_EPDG_TIMER_SEC = 62; // 0x3e + field public static final int KEY_LTE_THRESHOLD_1 = 56; // 0x38 + field public static final int KEY_LTE_THRESHOLD_2 = 57; // 0x39 + field public static final int KEY_LTE_THRESHOLD_3 = 58; // 0x3a + field public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3; // 0x3 + field public static final int KEY_MOBILE_DATA_ENABLED = 29; // 0x1d + field public static final int KEY_MULTIENDPOINT_ENABLED = 65; // 0x41 + field public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; // 0x13 + field public static final int KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC = 18; // 0x12 + field public static final int KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC = 20; // 0x14 + field public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17; // 0x11 + field public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23; // 0x17 + field public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22; // 0x16 + field public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; // 0x15 + field public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; // 0x10 + field public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; // 0xf + field public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; // 0xc + field public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; // 0x21 + field public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34; // 0x22 + field public static final int KEY_RTP_SPEECH_END_PORT = 36; // 0x24 + field public static final int KEY_RTP_SPEECH_START_PORT = 35; // 0x23 + field public static final int KEY_RTT_ENABLED = 66; // 0x42 + field public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43; // 0x2b + field public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44; // 0x2c + field public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38; // 0x26 + field public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4; // 0x4 + field public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37; // 0x25 + field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42; // 0x2a + field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39; // 0x27 + field public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32; // 0x20 + field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45; // 0x2d + field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40; // 0x28 + field public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46; // 0x2e + field public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41; // 0x29 + field public static final int KEY_SIP_SESSION_TIMER_SEC = 2; // 0x2 + field public static final int KEY_SMS_FORMAT = 13; // 0xd + field public static final int KEY_SMS_OVER_IP_ENABLED = 14; // 0xe + field public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54; // 0x36 + field public static final int KEY_T1_TIMER_VALUE_MS = 7; // 0x7 + field public static final int KEY_T2_TIMER_VALUE_MS = 8; // 0x8 + field public static final int KEY_TF_TIMER_VALUE_MS = 9; // 0x9 + field public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5; // 0x5 + field public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24; // 0x18 + field public static final int KEY_VIDEO_QUALITY = 55; // 0x37 + field public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28; // 0x1c field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a + field public static final int KEY_VOLTE_PROVISIONING_STATUS = 10; // 0xa + field public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30; // 0x1e + field public static final int KEY_VT_PROVISIONING_STATUS = 11; // 0xb + field public static final int KEY_WIFI_EPDG_TIMER_SEC = 63; // 0x3f + field public static final int KEY_WIFI_THRESHOLD_A = 60; // 0x3c + field public static final int KEY_WIFI_THRESHOLD_B = 61; // 0x3d + field public static final int PROVISIONING_RESULT_UNKNOWN = -1; // 0xffffffff field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0 field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1 + field public static final int SMS_FORMAT_3GPP = 1; // 0x1 + field public static final int SMS_FORMAT_3GPP2 = 0; // 0x0 field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC"; field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY"; + field public static final int VIDEO_QUALITY_HIGH = 1; // 0x1 + field public static final int VIDEO_QUALITY_LOW = 0; // 0x0 } public static class ProvisioningManager.Callback { @@ -3588,24 +3672,6 @@ package android.telephony.ims { method public void onProvisioningStringChanged(int, @NonNull String); } - public interface RegistrationManager { - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); - field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0 - field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2 - field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1 - } - - public static class RegistrationManager.RegistrationCallback { - ctor public RegistrationManager.RegistrationCallback(); - method public void onRegistered(int); - method public void onRegistering(int); - method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo); - method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo); - } - } package android.telephony.ims.feature { @@ -3629,6 +3695,7 @@ package android.telephony.ims.feature { public abstract class ImsFeature { ctor public ImsFeature(); method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method public int getFeatureState(); method public final int getSlotIndex(); method public abstract void onFeatureReady(); method public abstract void onFeatureRemoved(); @@ -3667,7 +3734,7 @@ package android.telephony.ims.feature { method public void onFeatureReady(); method public void onFeatureRemoved(); method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); - method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); + method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); method public void setUiTtyMode(int, @Nullable android.os.Message); method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]); field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; @@ -3683,10 +3750,6 @@ package android.telephony.ims.feature { method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); - field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 - field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 - field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 - field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1 } @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability { @@ -3777,6 +3840,7 @@ package android.telephony.ims.stub { method public String getConfigString(int); method public final void notifyProvisionedValueChanged(int, int); method public final void notifyProvisionedValueChanged(int, String); + method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method public int setConfig(int, int); method public int setConfig(int, String); field public static final int CONFIG_RESULT_FAILED = 1; // 0x1 @@ -3875,6 +3939,17 @@ package android.telephony.ims.stub { method public int updateClir(int); method public int updateColp(boolean); method public int updateColr(int); + field public static final int CALL_BARRING_ALL = 7; // 0x7 + field public static final int CALL_BARRING_ALL_INCOMING = 1; // 0x1 + field public static final int CALL_BARRING_ALL_OUTGOING = 2; // 0x2 + field public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; // 0x6 + field public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; // 0x9 + field public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; // 0x8 + field public static final int CALL_BARRING_OUTGOING_INTL = 3; // 0x3 + field public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; // 0x4 + field public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; // 0xa + field public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; // 0x5 + field public static final int INVALID_RESULT = -1; // 0xffffffff } } @@ -4059,138 +4134,10 @@ package android.util.proto { method public void writeRawZigZag64(long); } - public final class ProtoOutputStream extends android.util.proto.ProtoStream { - ctor public ProtoOutputStream(); - ctor public ProtoOutputStream(int); - ctor public ProtoOutputStream(java.io.OutputStream); - ctor public ProtoOutputStream(java.io.FileDescriptor); - method public static int checkFieldId(long, long); - method public void dump(String); - method public void end(long); - method @Deprecated public void endObject(long); - method @Deprecated public void endRepeatedObject(long); - method public void flush(); - method public byte[] getBytes(); - method public int getRawSize(); - method public static long makeFieldId(int, long); - method public long start(long); - method @Deprecated public long startObject(long); - method @Deprecated public long startRepeatedObject(long); - method public void write(long, double); - method public void write(long, float); - method public void write(long, int); - method public void write(long, long); - method public void write(long, boolean); - method public void write(long, String); - method public void write(long, byte[]); - method @Deprecated public void writeBool(long, boolean); - method @Deprecated public void writeBytes(long, byte[]); - method @Deprecated public void writeDouble(long, double); - method @Deprecated public void writeEnum(long, int); - method @Deprecated public void writeFixed32(long, int); - method @Deprecated public void writeFixed64(long, long); - method @Deprecated public void writeFloat(long, float); - method @Deprecated public void writeInt32(long, int); - method @Deprecated public void writeInt64(long, long); - method @Deprecated public void writeObject(long, byte[]); - method @Deprecated public void writePackedBool(long, boolean[]); - method @Deprecated public void writePackedDouble(long, double[]); - method @Deprecated public void writePackedEnum(long, int[]); - method @Deprecated public void writePackedFixed32(long, int[]); - method @Deprecated public void writePackedFixed64(long, long[]); - method @Deprecated public void writePackedFloat(long, float[]); - method @Deprecated public void writePackedInt32(long, int[]); - method @Deprecated public void writePackedInt64(long, long[]); - method @Deprecated public void writePackedSFixed32(long, int[]); - method @Deprecated public void writePackedSFixed64(long, long[]); - method @Deprecated public void writePackedSInt32(long, int[]); - method @Deprecated public void writePackedSInt64(long, long[]); - method @Deprecated public void writePackedUInt32(long, int[]); - method @Deprecated public void writePackedUInt64(long, long[]); - method @Deprecated public void writeRepeatedBool(long, boolean); - method @Deprecated public void writeRepeatedBytes(long, byte[]); - method @Deprecated public void writeRepeatedDouble(long, double); - method @Deprecated public void writeRepeatedEnum(long, int); - method @Deprecated public void writeRepeatedFixed32(long, int); - method @Deprecated public void writeRepeatedFixed64(long, long); - method @Deprecated public void writeRepeatedFloat(long, float); - method @Deprecated public void writeRepeatedInt32(long, int); - method @Deprecated public void writeRepeatedInt64(long, long); - method @Deprecated public void writeRepeatedObject(long, byte[]); - method @Deprecated public void writeRepeatedSFixed32(long, int); - method @Deprecated public void writeRepeatedSFixed64(long, long); - method @Deprecated public void writeRepeatedSInt32(long, int); - method @Deprecated public void writeRepeatedSInt64(long, long); - method @Deprecated public void writeRepeatedString(long, String); - method @Deprecated public void writeRepeatedUInt32(long, int); - method @Deprecated public void writeRepeatedUInt64(long, long); - method @Deprecated public void writeSFixed32(long, int); - method @Deprecated public void writeSFixed64(long, long); - method @Deprecated public void writeSInt32(long, int); - method @Deprecated public void writeSInt64(long, long); - method @Deprecated public void writeString(long, String); - method public void writeTag(int, int); - method @Deprecated public void writeUInt32(long, int); - method @Deprecated public void writeUInt64(long, long); - } - public class ProtoParseException extends java.lang.RuntimeException { ctor public ProtoParseException(String); } - public abstract class ProtoStream { - ctor public ProtoStream(); - method public static int convertObjectIdToOrdinal(int); - method public static int getDepthFromToken(long); - method public static String getFieldCountString(long); - method public static String getFieldIdString(long); - method public static String getFieldTypeString(long); - method public static int getObjectIdFromToken(long); - method public static int getOffsetFromToken(long); - method public static boolean getRepeatedFromToken(long); - method public static int getTagSizeFromToken(long); - method public static String getWireTypeString(int); - method public static long makeFieldId(int, long); - method public static long makeToken(int, boolean, int, int, int); - method public static String token2String(long); - field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L - field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L - field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L - field public static final int FIELD_COUNT_SHIFT = 40; // 0x28 - field public static final long FIELD_COUNT_SINGLE = 1099511627776L; // 0x10000000000L - field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L - field public static final int FIELD_ID_MASK = -8; // 0xfffffff8 - field public static final int FIELD_ID_SHIFT = 3; // 0x3 - field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L - field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L - field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L - field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L - field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L - field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L - field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L - field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L - field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L - field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L - field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L - field protected static final String[] FIELD_TYPE_NAMES; - field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L - field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L - field public static final int FIELD_TYPE_SHIFT = 32; // 0x20 - field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L - field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L - field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L - field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L - field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L - field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L - field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4 - field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5 - field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1 - field public static final int WIRE_TYPE_LENGTH_DELIMITED = 2; // 0x2 - field public static final int WIRE_TYPE_MASK = 7; // 0x7 - field public static final int WIRE_TYPE_START_GROUP = 3; // 0x3 - field public static final int WIRE_TYPE_VARINT = 0; // 0x0 - } - public class WireTypeMismatchException extends android.util.proto.ProtoParseException { ctor public WireTypeMismatchException(String); } diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java index 6033655c8513..c2ee6dcd13b2 100644 --- a/cmds/sm/src/com/android/commands/sm/Sm.java +++ b/cmds/sm/src/com/android/commands/sm/Sm.java @@ -103,6 +103,10 @@ public final class Sm { runSetVirtualDisk(); } else if ("set-isolated-storage".equals(op)) { runIsolatedStorage(); + } else if ("start-checkpoint".equals(op)) { + runStartCheckpoint(); + } else if ("supports-checkpoint".equals(op)) { + runSupportsCheckpoint(); } else { throw new IllegalArgumentException(); } @@ -313,6 +317,27 @@ public final class Sm { } } + private void runStartCheckpoint() throws RemoteException { + final String numRetriesString = nextArg(); + if (numRetriesString == null) { + throw new IllegalArgumentException("Expected <num-retries>"); + } + int numRetries; + try { + numRetries = Integer.parseInt(numRetriesString); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("<num-retries> must be a positive integer"); + } + if (numRetries <= 0) { + throw new IllegalArgumentException("<num-retries> must be a positive integer"); + } + mSm.startCheckpoint(numRetries); + } + + private void runSupportsCheckpoint() throws RemoteException { + System.out.println(mSm.supportsCheckpoint()); + } + private String nextArg() { if (mNextArg >= mArgs.length) { return null; @@ -344,6 +369,10 @@ public final class Sm { System.err.println(""); System.err.println(" sm set-isolated-storage [on|off|default]"); System.err.println(""); + System.err.println(" sm start-checkpoint <num-retries>"); + System.err.println(""); + System.err.println(" sm supports-checkpoint"); + System.err.println(""); return 1; } } diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 8944dedd6c96..da1a76f8169d 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -138,11 +138,57 @@ cc_defaults { "android.hardware.power@1.1", "android.hardware.power.stats@1.0", "libpackagelistparser", + "libstatsmetadata", "libsysutils", "libcutils", ], } +// ================ +// libstatsmetadata +// ================ + +genrule { + name: "atoms_info.h", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --atomsInfoHeader $(genDir)/atoms_info.h", + out: [ + "atoms_info.h", + ], +} + +genrule { + name: "atoms_info.cpp", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --atomsInfoCpp $(genDir)/atoms_info.cpp", + out: [ + "atoms_info.cpp", + ], +} + +cc_library_shared { + name: "libstatsmetadata", + host_supported: true, + generated_sources: [ + "atoms_info.cpp", + ], + generated_headers: [ + "atoms_info.h", + ], + cflags: [ + "-Wall", + "-Werror", + ], + export_generated_headers: [ + "atoms_info.h", + ], + shared_libs: [ + "libcutils", + "libstatslog", + ], +} + + // ========= // statsd // ========= diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS index 380e499a5abf..a61babf32e58 100644 --- a/cmds/statsd/OWNERS +++ b/cmds/statsd/OWNERS @@ -1,7 +1,9 @@ -jianjin@google.com +jeffreyhuang@google.com joeo@google.com jtnguyen@google.com muhammadq@google.com +ruchirr@google.com singhtejinder@google.com +tsaichristine@google.com yaochen@google.com yro@google.com diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp index 13f5c8ae5fd8..320a32ab4648 100644 --- a/cmds/statsd/src/FieldValue.cpp +++ b/cmds/statsd/src/FieldValue.cpp @@ -18,8 +18,8 @@ #include "Log.h" #include "FieldValue.h" #include "HashableDimensionKey.h" +#include "atoms_info.h" #include "math.h" -#include "statslog.h" namespace android { namespace os { diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index ff7416c4b9e0..c9e026bf231c 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -23,6 +23,7 @@ #include <frameworks/base/cmds/statsd/src/active_config_list.pb.h> #include "StatsLogProcessor.h" #include "android-base/stringprintf.h" +#include "atoms_info.h" #include "external/StatsPullerManager.h" #include "guardrail/StatsdStats.h" #include "metrics/CountMetricProducer.h" diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index c92315687e71..d9083886f817 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -50,6 +50,7 @@ import "frameworks/base/core/proto/android/stats/intelligence/enums.proto"; import "frameworks/base/core/proto/android/stats/launcher/launcher.proto"; import "frameworks/base/core/proto/android/stats/location/location_enums.proto"; import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto"; +import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto"; import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto"; import "frameworks/base/core/proto/android/stats/style/style_enums.proto"; import "frameworks/base/core/proto/android/telecomm/enums.proto"; @@ -123,10 +124,10 @@ message Atom { AppStartOccurred app_start_occurred = 48; AppStartCanceled app_start_canceled = 49; AppStartFullyDrawn app_start_fully_drawn = 50; - LmkKillOccurred lmk_kill_occurred = 51; + LmkKillOccurred lmk_kill_occurred = 51 [(log_from_module) = "lmkd"]; PictureInPictureStateChanged picture_in_picture_state_changed = 52; WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53; - LmkStateChanged lmk_state_changed = 54; + LmkStateChanged lmk_state_changed = 54 [(log_from_module) = "lmkd"]; AppStartMemoryStateCaptured app_start_memory_state_captured = 55; ShutdownSequenceReported shutdown_sequence_reported = 56; BootSequenceReported boot_sequence_reported = 57; @@ -322,6 +323,8 @@ message Atom { ExclusionRectStateChanged exclusion_rect_state_changed = 223; BackGesture back_gesture_reported_reported = 224; + UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225; + UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226; AppCompatibilityChangeReported app_compatibility_change_reported = 228 [(allow_from_any_uid) = true]; PerfettoUploaded perfetto_uploaded = @@ -6894,3 +6897,70 @@ message PerfettoUploaded { optional int64 trace_uuid_lsb = 2; optional int64 trace_uuid_msb = 3; } + +/** + * Information about an OTA update attempt by update_engine. + * Logged from platform/system/update_engine/metrics_reporter_android.cc + */ +message UpdateEngineUpdateAttemptReported { + // The number of attempts for the update engine to apply a given payload. + optional int32 attempt_number = 1; + + optional android.stats.otaupdate.PayloadType payload_type = 2; + + // The total time in minutes for the update engine to apply a given payload. + // The time is calculated by calling clock_gettime() / CLOCK_BOOTTIME; and + // it's increased when the system is sleeping. + optional int32 duration_boottime_in_minutes = 3; + + // The total time in minutes for the update engine to apply a given payload. + // The time is calculated by calling clock_gettime() / CLOCK_MONOTONIC_RAW; + // and it's not increased when the system is sleeping. + optional int32 duration_monotonic_in_minutes = 4; + + // The size of the payload in MiBs. + optional int32 payload_size_mib = 5; + + // The attempt result reported by the update engine for an OTA update. + optional android.stats.otaupdate.AttemptResult attempt_result = 6; + + // The error code reported by the update engine after an OTA update attempt + // on A/B devices. + optional android.stats.otaupdate.ErrorCode error_code = 7; + + // The build fingerprint of the source system. The value is read from a + // system property when the device takes the update. e.g. + // Android/aosp_sailfish/sailfish:10/QP1A.190425.004/5507117:userdebug/test-keys + optional string source_fingerprint = 8; +} + +/** + * Information about all the attempts the device make before finishing the + * successful update. + * Logged from platform/system/update_engine/metrics_reporter_android.cc + */ +message UpdateEngineSuccessfulUpdateReported { + // The number of attempts for the update engine to apply the payload for a + // successful update. + optional int32 attempt_count = 1; + + optional android.stats.otaupdate.PayloadType payload_type = 2; + + optional int32 payload_size_mib = 3; + + // The total number of bytes downloaded by update_engine since the last + // successful update. + optional int32 total_bytes_downloaded_mib = 4; + + // The ratio in percentage of the over-downloaded bytes compared to the + // total bytes needed to successfully install the update. e.g. 200 if we + // download 200MiB in total for a 100MiB package. + optional int32 download_overhead_percentage = 5; + + // The total time in minutes for the update engine to apply the payload for a + // successful update. + optional int32 total_duration_minutes = 6; + + // The number of reboot of the device during a successful update. + optional int32 reboot_count = 7; +} diff --git a/cmds/statsd/src/external/PowerStatsPuller.cpp b/cmds/statsd/src/external/PowerStatsPuller.cpp index b142caca3acc..dc69b78f0329 100644 --- a/cmds/statsd/src/external/PowerStatsPuller.cpp +++ b/cmds/statsd/src/external/PowerStatsPuller.cpp @@ -22,6 +22,7 @@ #include <vector> #include "PowerStatsPuller.h" +#include "statslog.h" #include "stats_log_util.h" using android::hardware::hidl_vec; diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp index 0b9b6abfd6d6..ccfd666573c4 100644 --- a/cmds/statsd/src/external/puller_util.cpp +++ b/cmds/statsd/src/external/puller_util.cpp @@ -18,8 +18,8 @@ #include "Log.h" #include "StatsPullerManager.h" +#include "atoms_info.h" #include "puller_util.h" -#include "statslog.h" namespace android { namespace os { diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 23d2aceb4fc3..564b9ee8051c 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -16,7 +16,7 @@ #pragma once #include "config/ConfigKey.h" -#include "statslog.h" +#include "atoms_info.h" #include <gtest/gtest_prod.h> #include <log/log_time.h> diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 963205ee56f4..7b7d0cac0d30 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -19,6 +19,7 @@ #include "statslog.h" #include "CountMetricProducer.h" +#include "atoms_info.h" #include "condition/CombinationConditionTracker.h" #include "condition/SimpleConditionTracker.h" #include "guardrail/StatsdStats.h" diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 5cfb1239d30e..46442b57126c 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -32,8 +32,8 @@ #include "../metrics/GaugeMetricProducer.h" #include "../metrics/ValueMetricProducer.h" +#include "atoms_info.h" #include "stats_util.h" -#include "statslog.h" #include <inttypes.h> diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h index bfb84cf4d1b9..a28165d09cdf 100644 --- a/cmds/statsd/src/stats_log_util.h +++ b/cmds/statsd/src/stats_log_util.h @@ -19,9 +19,9 @@ #include <android/util/ProtoOutputStream.h> #include "FieldValue.h" #include "HashableDimensionKey.h" +#include "atoms_info.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "guardrail/StatsdStats.h" -#include "statslog.h" namespace android { namespace os { diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp index bdc52b0af34c..32409184b02f 100644 --- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp +++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp @@ -24,6 +24,7 @@ #include <log/log.h> #include "src/external/GpuStatsPuller.h" +#include "statslog.h" #ifdef __ANDROID__ diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp index 266ea351b5d4..673082834e18 100644 --- a/cmds/statsd/tests/external/puller_util_test.cpp +++ b/cmds/statsd/tests/external/puller_util_test.cpp @@ -17,6 +17,7 @@ #include <gtest/gtest.h> #include <stdio.h> #include <vector> +#include "statslog.h" #include "../metrics/metrics_test_helper.h" #ifdef __ANDROID__ diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index 2ac8409f8e1a..773942c8b753 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -14142,7 +14142,6 @@ HSPLandroid/telephony/ServiceState;->convertNetworkTypeBitmaskToBearerBitmask(I) HSPLandroid/telephony/ServiceState;->copyFrom(Landroid/telephony/ServiceState;)V HSPLandroid/telephony/ServiceState;->describeContents()I HSPLandroid/telephony/ServiceState;->equals(Ljava/lang/Object;)Z -HSPLandroid/telephony/ServiceState;->fillInNotifierBundle(Landroid/os/Bundle;)V HSPLandroid/telephony/ServiceState;->getCdmaDefaultRoamingIndicator()I HSPLandroid/telephony/ServiceState;->getCdmaEriIconIndex()I HSPLandroid/telephony/ServiceState;->getCdmaEriIconMode()I diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 90b80e73c323..842c3ef7dcdc 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -21,8 +21,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.UnsupportedAppUsage; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index cf24b8e1ffa6..8e1ac7623e45 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -20,7 +20,7 @@ import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; import android.annotation.IntDef; import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java index c822d20445ec..9a18880a353b 100644 --- a/core/java/android/accounts/Account.java +++ b/core/java/android/accounts/Account.java @@ -18,7 +18,7 @@ package android.accounts; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/accounts/AccountAndUser.java b/core/java/android/accounts/AccountAndUser.java index b0d53438d97c..fd6739410ce2 100644 --- a/core/java/android/accounts/AccountAndUser.java +++ b/core/java/android/accounts/AccountAndUser.java @@ -16,7 +16,7 @@ package android.accounts; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Used to store the Account and the UserId this account is associated with. diff --git a/core/java/android/accounts/AccountAuthenticatorResponse.java b/core/java/android/accounts/AccountAuthenticatorResponse.java index bb2e327a9be8..a2a57990297c 100644 --- a/core/java/android/accounts/AccountAuthenticatorResponse.java +++ b/core/java/android/accounts/AccountAuthenticatorResponse.java @@ -16,10 +16,10 @@ package android.accounts; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.util.Log; diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index c80be8e5c3fa..7ecaacae6b09 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -25,8 +25,8 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.Size; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; diff --git a/core/java/android/accounts/AuthenticatorDescription.java b/core/java/android/accounts/AuthenticatorDescription.java index 555639445e85..b7bf11d4d5b6 100644 --- a/core/java/android/accounts/AuthenticatorDescription.java +++ b/core/java/android/accounts/AuthenticatorDescription.java @@ -16,10 +16,10 @@ package android.accounts; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; /** * A {@link Parcelable} value type that contains information about an account authenticator. diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index 17d54d2455fe..3cdd691fd5dd 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -17,7 +17,7 @@ package android.animation; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ConstantState; diff --git a/core/java/android/animation/ArgbEvaluator.java b/core/java/android/animation/ArgbEvaluator.java index 5b69d18a8386..9519ddde86f4 100644 --- a/core/java/android/animation/ArgbEvaluator.java +++ b/core/java/android/animation/ArgbEvaluator.java @@ -16,7 +16,7 @@ package android.animation; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * This evaluator can be used to perform type interpolation between integer diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java index c7537102d40c..21f0b6b2ae62 100644 --- a/core/java/android/animation/LayoutTransition.java +++ b/core/java/android/animation/LayoutTransition.java @@ -16,7 +16,7 @@ package android.animation; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.view.View; import android.view.ViewGroup; diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 764e5992fbd9..ca37e9b107a0 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -19,7 +19,7 @@ package android.animation; import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Looper; import android.os.Trace; diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index e57327991a82..504364c8c1d9 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -22,7 +22,7 @@ import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index bf7b2f8b7be4..b6f61a2b8f01 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -33,10 +33,10 @@ import android.annotation.RequiresPermission; import android.annotation.StyleRes; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.VoiceInteractor.Request; import android.app.admin.DevicePolicyManager; import android.app.assist.AssistContent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.ContentResolver; diff --git a/core/java/android/app/ActivityGroup.java b/core/java/android/app/ActivityGroup.java index d4aa01b8f43e..cb06eea2059e 100644 --- a/core/java/android/app/ActivityGroup.java +++ b/core/java/android/app/ActivityGroup.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Bundle; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index e8e4085f731d..726a6195efc5 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -27,7 +27,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 607ef185ae60..b9eb95739aa1 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -15,7 +15,7 @@ */ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.IBinder; diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 926044bffdd0..10bee4013de0 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -25,7 +25,7 @@ import static android.view.Display.INVALID_DISPLAY; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index 4ef554dc64cc..28d4c7f8a448 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -19,7 +19,7 @@ package android.app; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 4e8bee24052e..c4281f0b8d28 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -32,7 +32,6 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.BackupAgent; @@ -46,6 +45,7 @@ import android.app.servertransaction.PendingTransactionActions; import android.app.servertransaction.PendingTransactionActions.StopInfo; import android.app.servertransaction.TransactionExecutor; import android.app.servertransaction.TransactionExecutorHelper; +import android.compat.annotation.UnsupportedAppUsage; import android.content.AutofillOptions; import android.content.BroadcastReceiver; import android.content.ComponentCallbacks2; diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index 3a34b7926611..a0040ffd13fa 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -21,7 +21,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.os.Build; diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index bfc216a24c1b..4c347373d642 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -21,7 +21,7 @@ import android.annotation.AttrRes; import android.annotation.DrawableRes; import android.annotation.StringRes; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.res.ResourceId; diff --git a/core/java/android/app/AppGlobals.java b/core/java/android/app/AppGlobals.java index 1f737b60964c..552d6e9334e2 100644 --- a/core/java/android/app/AppGlobals.java +++ b/core/java/android/app/AppGlobals.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.IPackageManager; /** diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 33d83f9b123b..6ff48eac6ca5 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -25,8 +25,8 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.usage.UsageStatsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -720,7 +720,18 @@ public class AppOpsManager { /** @hide Capture the device's display contents and/or audio */ @UnsupportedAppUsage public static final int OP_PROJECT_MEDIA = 46; - /** @hide Activate a VPN connection without user intervention. */ + + /** + * Start (without additional user intervention) a VPN connection, as used by {@link + * android.net.VpnService} along with as Platform VPN connections, as used by {@link + * android.net.VpnManager} + * + * <p>This appop is granted to apps that have already been given user consent to start + * VpnService based VPN connections. As this is a superset of OP_ACTIVATE_PLATFORM_VPN, this + * appop also allows the starting of Platform VPNs. + * + * @hide + */ @UnsupportedAppUsage public static final int OP_ACTIVATE_VPN = 47; /** @hide Access the WallpaperManagerAPI to write wallpapers. */ @@ -840,10 +851,21 @@ public class AppOpsManager { public static final int OP_READ_DEVICE_IDENTIFIERS = 89; /** @hide Read location metadata from media */ public static final int OP_ACCESS_MEDIA_LOCATION = 90; + /** + * Start (without additional user intervention) a Platform VPN connection, as used by {@link + * android.net.VpnManager} + * + * <p>This appop is granted to apps that have already been given user consent to start Platform + * VPN connections. This appop is insufficient to start VpnService based VPNs (but the opposite + * is true). + * + * @hide + */ + public static final int OP_ACTIVATE_PLATFORM_VPN = 91; /** @hide */ @UnsupportedAppUsage - public static final int _NUM_OP = 91; + public static final int _NUM_OP = 92; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1122,6 +1144,8 @@ public class AppOpsManager { public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility"; /** @hide Read device identifiers */ public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers"; + /** @hide Start Platform VPN without user intervention */ + public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn"; // Warning: If an permission is added here it also has to be added to // com.android.packageinstaller.permission.utils.EventLogger @@ -1285,6 +1309,7 @@ public class AppOpsManager { OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY OP_READ_DEVICE_IDENTIFIERS, // READ_DEVICE_IDENTIFIERS OP_ACCESS_MEDIA_LOCATION, // ACCESS_MEDIA_LOCATION + OP_ACTIVATE_PLATFORM_VPN, // ACTIVATE_PLATFORM_VPN }; /** @@ -1382,6 +1407,7 @@ public class AppOpsManager { OPSTR_ACCESS_ACCESSIBILITY, OPSTR_READ_DEVICE_IDENTIFIERS, OPSTR_ACCESS_MEDIA_LOCATION, + OPSTR_ACTIVATE_PLATFORM_VPN, }; /** @@ -1480,6 +1506,7 @@ public class AppOpsManager { "ACCESS_ACCESSIBILITY", "READ_DEVICE_IDENTIFIERS", "ACCESS_MEDIA_LOCATION", + "ACTIVATE_PLATFORM_VPN" }; /** @@ -1579,6 +1606,7 @@ public class AppOpsManager { null, // no permission for OP_ACCESS_ACCESSIBILITY null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS Manifest.permission.ACCESS_MEDIA_LOCATION, + null, // no permission for OP_ACTIVATE_PLATFORM_VPN }; /** @@ -1678,6 +1706,7 @@ public class AppOpsManager { null, // ACCESS_ACCESSIBILITY null, // READ_DEVICE_IDENTIFIERS null, // ACCESS_MEDIA_LOCATION + null, // ACTIVATE_PLATFORM_VPN }; /** @@ -1776,6 +1805,7 @@ public class AppOpsManager { false, // ACCESS_ACCESSIBILITY false, // READ_DEVICE_IDENTIFIERS false, // ACCESS_MEDIA_LOCATION + false, // ACTIVATE_PLATFORM_VPN }; /** @@ -1873,6 +1903,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS AppOpsManager.MODE_ALLOWED, // ALLOW_MEDIA_LOCATION + AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN }; /** @@ -1974,6 +2005,7 @@ public class AppOpsManager { false, // ACCESS_ACCESSIBILITY false, // READ_DEVICE_IDENTIFIERS false, // ACCESS_MEDIA_LOCATION + false, // ACTIVATE_PLATFORM_VPN }; /** diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 08cad04401e9..996939eb9ee1 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -16,7 +16,6 @@ package android.app; -import android.annotation.NonNull; import android.util.SparseIntArray; import com.android.internal.util.function.QuadFunction; @@ -77,38 +76,10 @@ public abstract class AppOpsManagerInternal { public abstract void setDeviceAndProfileOwners(SparseIntArray owners); /** - * Sets the app-ops mode for a certain app-op and uid. - * - * <p>Similar as {@link AppOpsManager#setUidMode} but does not require the package manager to be - * working. Hence this can be used very early during boot. - * - * <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid. - * - * @param code The op code to set. - * @param uid The UID for which to set. - * @param mode The new mode to set. - */ - public abstract void setUidMode(int code, int uid, int mode); - - /** * Set all {@link #setMode (package) modes} for this uid to the default value. * * @param code The app-op * @param uid The uid */ public abstract void setAllPkgModesToDefault(int code, int uid); - - /** - * Get the (raw) mode of an app-op. - * - * <p>Does <u>not</u> verify that package belongs to uid. The caller needs to do that. - * - * @param code The code of the op - * @param uid The uid of the package the op belongs to - * @param packageName The package the op belongs to - * - * @return The mode of the op - */ - public abstract @AppOpsManager.Mode int checkOperationUnchecked(int code, int uid, - @NonNull String packageName); } diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index e12942f248d4..941467fad736 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -19,7 +19,7 @@ package android.app; import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks; import android.content.ComponentCallbacks2; import android.content.Context; diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 2e59b903f06d..bac432e42318 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.GraphicsEnvironment; diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 835769f69951..1158c44e63c0 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -20,9 +20,9 @@ import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.annotation.XmlRes; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java index 004dca1a708f..3d745831ce1c 100644 --- a/core/java/android/app/ContentProviderHolder.java +++ b/core/java/android/app/ContentProviderHolder.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProviderNative; import android.content.IContentProvider; import android.content.pm.ProviderInfo; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index d317c34c6518..ce4d312318d4 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.AutofillOptions; import android.content.BroadcastReceiver; import android.content.ComponentName; diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java index 9d82ffa838ca..195c3e1c296a 100644 --- a/core/java/android/app/DatePickerDialog.java +++ b/core/java/android/app/DatePickerDialog.java @@ -19,7 +19,7 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 088c245c9c2c..10525f7afc54 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -24,7 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java index bfc15c221702..e4c84d7e7997 100644 --- a/core/java/android/app/DialogFragment.java +++ b/core/java/android/app/DialogFragment.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 77a777024a21..bcc08e9a96fb 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -22,7 +22,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentUris; diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 4f121aa35f7c..c6a0de458df0 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -21,7 +21,7 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java index 9316be7a7968..f021f7690283 100644 --- a/core/java/android/app/FragmentController.java +++ b/core/java/android/app/FragmentController.java @@ -17,7 +17,7 @@ package android.app; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java index 26b4a11f4c10..9e887b88c407 100644 --- a/core/java/android/app/FragmentHostCallback.java +++ b/core/java/android/app/FragmentHostCallback.java @@ -18,7 +18,7 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.IntentSender; diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 68daf44b19a5..904c4735e0ff 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -22,7 +22,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 9720e9f47f83..cff6411c882c 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -19,7 +19,7 @@ package android.app; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java index 74fb99a0909f..71b28fba6019 100644 --- a/core/java/android/app/IntentService.java +++ b/core/java/android/app/IntentService.java @@ -16,9 +16,9 @@ package android.app; -import android.annotation.UnsupportedAppUsage; -import android.annotation.WorkerThread; import android.annotation.Nullable; +import android.annotation.WorkerThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Handler; import android.os.HandlerThread; diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 667758755c99..376acfaa6d90 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -23,8 +23,8 @@ import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.trust.ITrustManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 4efaaad91eb6..2a72d43eccad 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -18,7 +18,7 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 19575b2b36ba..1d27f8fb6dbc 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -16,9 +16,9 @@ package android.app; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread.ActivityClientRecord; import android.app.servertransaction.PendingTransactionActions; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.Binder; diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java index 25eb958b61e3..74bc9e215106 100644 --- a/core/java/android/app/NativeActivity.java +++ b/core/java/android/app/NativeActivity.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 412ef04c2284..cefec441e702 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -33,7 +33,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.LocusId; diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 69ec831b5d1d..8ad2b36ae0da 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -15,13 +15,13 @@ */ package android.app; -import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.annotation.SystemApi.Client.MODULE_APPS; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager.Importance; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -319,9 +319,14 @@ public final class NotificationChannel implements Parcelable { } /** + * Allows users to block notifications sent through this channel, if this channel belongs to + * a package that is signed with the system signature. If the channel does not belong to a + * package that is signed with the system signature, this method does nothing. + * @param blockableSystem if {@code true}, allows users to block notifications on this channel. * @hide */ - @UnsupportedAppUsage + @SystemApi(client = MODULE_APPS) + @TestApi public void setBlockableSystem(boolean blockableSystem) { mBlockableSystem = blockableSystem; } @@ -641,6 +646,7 @@ public final class NotificationChannel implements Parcelable { /** * @hide */ + @TestApi public boolean isBlockableSystem() { return mBlockableSystem; } diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java index a8ee414cac0a..afbd0b5afe1c 100644 --- a/core/java/android/app/NotificationChannelGroup.java +++ b/core/java/android/app/NotificationChannelGroup.java @@ -17,7 +17,7 @@ package android.app; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index c6aa4fd86594..e25558f16f26 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -23,8 +23,8 @@ import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.Notification.Builder; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/app/PackageDeleteObserver.java b/core/java/android/app/PackageDeleteObserver.java index b7b0b192e7ae..d8803aa13e42 100644 --- a/core/java/android/app/PackageDeleteObserver.java +++ b/core/java/android/app/PackageDeleteObserver.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.pm.IPackageDeleteObserver2; diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java index 50031e0e4d35..0820367db1f8 100644 --- a/core/java/android/app/PackageInstallObserver.java +++ b/core/java/android/app/PackageInstallObserver.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.pm.IPackageInstallObserver2; import android.os.Bundle; diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 6f7a0607cbdb..6acbf21e5602 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -19,7 +19,7 @@ package android.app; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; diff --git a/core/java/android/app/PictureInPictureArgs.java b/core/java/android/app/PictureInPictureArgs.java index 3ee51739e455..9d49d107c99e 100644 --- a/core/java/android/app/PictureInPictureArgs.java +++ b/core/java/android/app/PictureInPictureArgs.java @@ -17,7 +17,7 @@ package android.app; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index cb72d4d5dc2c..f864fb57d00a 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -20,24 +20,24 @@ import static android.content.Context.DISPLAY_SERVICE; import static android.content.Context.WINDOW_SERVICE; import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; -import android.os.Handler; -import android.os.Message; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.TypedValue; /** * Base class for presentations. diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java index 3193eb89ac80..432fae5e9033 100644 --- a/core/java/android/app/ProgressDialog.java +++ b/core/java/android/app/ProgressDialog.java @@ -16,9 +16,7 @@ package android.app; -import com.android.internal.R; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; @@ -34,6 +32,8 @@ import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; +import com.android.internal.R; + import java.text.NumberFormat; /** diff --git a/core/java/android/app/QueuedWork.java b/core/java/android/app/QueuedWork.java index 76265390fe1a..82cc2c4daa0b 100644 --- a/core/java/android/app/QueuedWork.java +++ b/core/java/android/app/QueuedWork.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index e9ae60f23cf2..7d742f7e11eb 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -20,7 +20,7 @@ import static android.app.ActivityThread.DEBUG_CONFIGURATION; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.ApkAssets; diff --git a/core/java/android/app/ResultInfo.java b/core/java/android/app/ResultInfo.java index 9ee0f3126432..979d3dbf36a7 100644 --- a/core/java/android/app/ResultInfo.java +++ b/core/java/android/app/ResultInfo.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 8493fb25b8a5..9fe894b75455 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -17,7 +17,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index acca6fc177b8..93107ad4bfcb 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -17,7 +17,7 @@ package android.app; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.ContentResolver; diff --git a/core/java/android/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java index a01cec7aa944..83eb2ee1da14 100644 --- a/core/java/android/app/SearchableInfo.java +++ b/core/java/android/app/SearchableInfo.java @@ -16,17 +16,14 @@ package android.app; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; -import android.content.pm.ProviderInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ProviderInfo; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.os.Parcel; @@ -38,6 +35,9 @@ import android.util.Log; import android.util.Xml; import android.view.inputmethod.EditorInfo; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.util.HashMap; diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 9b62e3b3af98..dc8269f900b7 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -21,7 +21,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.Context; diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java index 0f8976fe924a..3783d1c52ab1 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -17,7 +17,7 @@ package android.app; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.SharedPreferences; import android.os.FileUtils; import android.os.Looper; diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 28413be29a1d..078e4538c66b 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -23,7 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; import android.os.IBinder; @@ -153,6 +153,11 @@ public class StatusBarManager { */ public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_ROTATE_SUGGESTIONS; + /** + * disable flags to be applied when the device is sim-locked. + */ + private static final int DEFAULT_SIM_LOCKED_DISABLED_FLAGS = DISABLE_EXPAND; + /** @hide */ public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0; /** @hide */ @@ -385,6 +390,30 @@ public class StatusBarManager { } /** + * Enable or disable expansion of the status bar. When the device is SIM-locked, the status + * bar should not be expandable. + * + * @param disabled If {@code true}, the status bar will be set to non-expandable. If + * {@code false}, re-enables expansion of the status bar. + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(android.Manifest.permission.STATUS_BAR) + public void setDisabledForSimNetworkLock(boolean disabled) { + try { + final int userId = Binder.getCallingUserHandle().getIdentifier(); + final IStatusBarService svc = getService(); + if (svc != null) { + svc.disableForUser(disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE, + mToken, mContext.getPackageName(), userId); + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * Get this app's currently requested disabled components * * @return a new DisableInfo diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 82df702eb7e5..88976e182e6d 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -341,6 +341,14 @@ final class SystemServiceRegistry { } }); + registerService(Context.NETWORK_STACK_SERVICE, IBinder.class, + new StaticServiceFetcher<IBinder>() { + @Override + public IBinder createService() { + return ServiceManager.getService(Context.NETWORK_STACK_SERVICE); + } + }); + registerService(Context.TETHERING_SERVICE, TetheringManager.class, new CachedServiceFetcher<TetheringManager>() { @Override diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index de64db9def64..fe9c64038909 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -18,7 +18,7 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.res.Configuration; diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index 50130400deab..6247187bbfab 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -16,8 +16,8 @@ package android.app; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager.TaskSnapshot; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Binder; import android.os.IBinder; diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java index 1b281d521957..c529297b14db 100644 --- a/core/java/android/app/TimePickerDialog.java +++ b/core/java/android/app/TimePickerDialog.java @@ -17,7 +17,7 @@ package android.app; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 3935628b707f..20e31cab4b00 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -24,7 +24,7 @@ import android.accessibilityservice.IAccessibilityServiceConnection; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index f251b3eb4a15..5f89e5c2a9b0 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -19,6 +19,7 @@ package android.app; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceClient; import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.IPackageManager; import android.graphics.Bitmap; @@ -40,8 +41,6 @@ import android.view.WindowContentFrameStats; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.IAccessibilityManager; -import dalvik.annotation.compat.UnsupportedAppUsage; - import libcore.io.IoUtils; import java.io.FileInputStream; diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index 83247875c8a5..6582d240554b 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -23,7 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.os.RemoteException; diff --git a/core/java/android/app/UserSwitchObserver.java b/core/java/android/app/UserSwitchObserver.java index 2f8ee744bfd6..6abc4f09ba38 100644 --- a/core/java/android/app/UserSwitchObserver.java +++ b/core/java/android/app/UserSwitchObserver.java @@ -16,7 +16,7 @@ package android.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IRemoteCallback; import android.os.RemoteException; diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java index c74f8c389c20..08a210b069b9 100644 --- a/core/java/android/app/VrManager.java +++ b/core/java/android/app/VrManager.java @@ -6,7 +6,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.os.RemoteException; diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 325a54bffbfb..102de950a129 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -26,7 +26,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 74237b4bfcb1..f4240b1c8a46 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -26,6 +26,7 @@ import static android.view.Surface.rotationToString; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Parcel; @@ -35,8 +36,6 @@ import android.util.proto.ProtoOutputStream; import android.util.proto.WireTypeMismatchException; import android.view.DisplayInfo; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.IOException; /** diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java index 00903c43b291..3cc7f1e5df42 100644 --- a/core/java/android/app/admin/DeviceAdminInfo.java +++ b/core/java/android/app/admin/DeviceAdminInfo.java @@ -17,7 +17,7 @@ package android.app.admin; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index a17b2ddd7215..79a2c9010f35 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -33,13 +33,13 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; import android.app.IServiceConnection; import android.app.KeyguardManager; import android.app.admin.SecurityLog.SecurityEvent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -6993,7 +6993,9 @@ public class DevicePolicyManager { * @param userHandle The user for whom to check the caller-id permission * @hide */ - public boolean getBluetoothContactSharingDisabled(UserHandle userHandle) { + @SystemApi + @RequiresPermission(permission.INTERACT_ACROSS_USERS) + public boolean getBluetoothContactSharingDisabled(@NonNull UserHandle userHandle) { if (mService != null) { try { return mService.getBluetoothContactSharingDisabledForUser(userHandle diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java index 972762152d3a..f0b87a8e2561 100644 --- a/core/java/android/app/admin/SecurityLog.java +++ b/core/java/android/app/admin/SecurityLog.java @@ -18,7 +18,7 @@ package android.app.admin; import android.annotation.IntDef; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/app/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java index db6ae4f2260a..e5316bc05749 100644 --- a/core/java/android/app/assist/AssistContent.java +++ b/core/java/android/app/assist/AssistContent.java @@ -1,6 +1,6 @@ package android.app.assist; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.Intent; import android.net.Uri; diff --git a/core/java/android/app/backup/BackupDataInput.java b/core/java/android/app/backup/BackupDataInput.java index 2a98ca715a26..d1383c8d0a6a 100644 --- a/core/java/android/app/backup/BackupDataInput.java +++ b/core/java/android/app/backup/BackupDataInput.java @@ -17,7 +17,7 @@ package android.app.backup; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.FileDescriptor; import java.io.IOException; diff --git a/core/java/android/app/backup/BackupDataInputStream.java b/core/java/android/app/backup/BackupDataInputStream.java index 08880665d921..11a3d0c3d725 100644 --- a/core/java/android/app/backup/BackupDataInputStream.java +++ b/core/java/android/app/backup/BackupDataInputStream.java @@ -16,9 +16,10 @@ package android.app.backup; -import android.annotation.UnsupportedAppUsage; -import java.io.InputStream; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.IOException; +import java.io.InputStream; /** * Provides an {@link java.io.InputStream}-like interface for accessing an diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java index 01961e78777f..fb161d41acd2 100644 --- a/core/java/android/app/backup/BackupDataOutput.java +++ b/core/java/android/app/backup/BackupDataOutput.java @@ -17,7 +17,7 @@ package android.app.backup; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelFileDescriptor; import java.io.FileDescriptor; diff --git a/core/java/android/app/backup/BackupHelperDispatcher.java b/core/java/android/app/backup/BackupHelperDispatcher.java index e9acdbfb61b9..6faa887206c1 100644 --- a/core/java/android/app/backup/BackupHelperDispatcher.java +++ b/core/java/android/app/backup/BackupHelperDispatcher.java @@ -16,7 +16,7 @@ package android.app.backup; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelFileDescriptor; import android.util.Log; diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java index 25caaaa6e5ad..dc815b631e46 100644 --- a/core/java/android/app/backup/BackupManager.java +++ b/core/java/android/app/backup/BackupManager.java @@ -21,7 +21,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/app/backup/FileBackupHelperBase.java b/core/java/android/app/backup/FileBackupHelperBase.java index 0caab983448b..5ad5d0865e56 100644 --- a/core/java/android/app/backup/FileBackupHelperBase.java +++ b/core/java/android/app/backup/FileBackupHelperBase.java @@ -16,7 +16,7 @@ package android.app.backup; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.ParcelFileDescriptor; import android.util.Log; diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java index 9a595b2da59f..587e883edaf2 100644 --- a/core/java/android/app/backup/FullBackup.java +++ b/core/java/android/app/backup/FullBackup.java @@ -16,7 +16,7 @@ package android.app.backup; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.XmlResourceParser; diff --git a/core/java/android/app/backup/FullBackupDataOutput.java b/core/java/android/app/backup/FullBackupDataOutput.java index 0ce86534afdd..d8fa0f586b7a 100644 --- a/core/java/android/app/backup/FullBackupDataOutput.java +++ b/core/java/android/app/backup/FullBackupDataOutput.java @@ -1,6 +1,6 @@ package android.app.backup; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelFileDescriptor; /** diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index a8f89df8058c..72eea849cbf4 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -29,7 +29,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ComponentName; import android.net.NetworkRequest; diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java index dadfe3d3746a..763520272e2e 100644 --- a/core/java/android/app/job/JobParameters.java +++ b/core/java/android/app/job/JobParameters.java @@ -18,8 +18,7 @@ package android.app.job; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; -import android.app.job.IJobCallback; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.net.Network; import android.net.Uri; diff --git a/core/java/android/app/job/JobWorkItem.java b/core/java/android/app/job/JobWorkItem.java index a055ab48c766..237c5071a130 100644 --- a/core/java/android/app/job/JobWorkItem.java +++ b/core/java/android/app/job/JobWorkItem.java @@ -19,7 +19,7 @@ package android.app.job; import static android.app.job.JobInfo.NETWORK_BYTES_UNKNOWN; import android.annotation.BytesLong; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java index bb04a2e52712..b9cda6c7c183 100644 --- a/core/java/android/app/role/RoleManager.java +++ b/core/java/android/app/role/RoleManager.java @@ -629,9 +629,12 @@ public final class RoleManager { * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)} * + * @param userId The user ID to get the default SMS package for. + * @return the package name of the default SMS app, or {@code null} if not configured. * @hide */ @Nullable + @SystemApi public String getDefaultSmsPackage(@UserIdInt int userId) { try { return mService.getDefaultSmsPackage(userId); diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java index 52ec3e60a9c7..4e743caccad6 100644 --- a/core/java/android/app/servertransaction/ActivityResultItem.java +++ b/core/java/android/app/servertransaction/ActivityResultItem.java @@ -18,9 +18,9 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; -import android.annotation.UnsupportedAppUsage; import android.app.ClientTransactionHandler; import android.app.ResultInfo; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java index b08e5973faa2..4d2e9a503ac5 100644 --- a/core/java/android/app/servertransaction/ClientTransaction.java +++ b/core/java/android/app/servertransaction/ClientTransaction.java @@ -17,9 +17,9 @@ package android.app.servertransaction; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ClientTransactionHandler; import android.app.IApplicationThread; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 1236e0ac7401..6d674ae7df14 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -18,11 +18,11 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ProfilerInfo; import android.app.ResultInfo; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo; diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java index bb775fc4a5fb..6a4996da38ca 100644 --- a/core/java/android/app/servertransaction/NewIntentItem.java +++ b/core/java/android/app/servertransaction/NewIntentItem.java @@ -19,8 +19,8 @@ package android.app.servertransaction; import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; -import android.annotation.UnsupportedAppUsage; import android.app.ClientTransactionHandler; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl index 9877fc741b7b..de8f4700de2d 100644 --- a/core/java/android/app/timedetector/ITimeDetectorService.aidl +++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl @@ -17,6 +17,7 @@ package android.app.timedetector; import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.NetworkTimeSuggestion; import android.app.timedetector.PhoneTimeSuggestion; /** @@ -35,4 +36,5 @@ import android.app.timedetector.PhoneTimeSuggestion; interface ITimeDetectorService { void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion); void suggestManualTime(in ManualTimeSuggestion timeSuggestion); + void suggestNetworkTime(in NetworkTimeSuggestion timeSuggestion); } diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java index 55f92be14cd0..50de73855511 100644 --- a/core/java/android/app/timedetector/ManualTimeSuggestion.java +++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; -import android.util.TimestampedValue; +import android.os.TimestampedValue; import java.util.ArrayList; import java.util.Arrays; diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.aidl b/core/java/android/app/timedetector/NetworkTimeSuggestion.aidl new file mode 100644 index 000000000000..731c907f6837 --- /dev/null +++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.aidl @@ -0,0 +1,19 @@ +/* + * 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.app.timedetector; + +parcelable NetworkTimeSuggestion; diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java new file mode 100644 index 000000000000..17e9c5a79fa5 --- /dev/null +++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java @@ -0,0 +1,129 @@ +/* + * 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.app.timedetector; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.TimestampedValue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * A time signal from a network time source like NTP. The value consists of the number of + * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime + * clock when that number was established. The elapsed realtime clock is considered accurate but + * volatile, so time signals must not be persisted across device resets. + * + * @hide + */ +public final class NetworkTimeSuggestion implements Parcelable { + + public static final @NonNull Creator<NetworkTimeSuggestion> CREATOR = + new Creator<NetworkTimeSuggestion>() { + public NetworkTimeSuggestion createFromParcel(Parcel in) { + return NetworkTimeSuggestion.createFromParcel(in); + } + + public NetworkTimeSuggestion[] newArray(int size) { + return new NetworkTimeSuggestion[size]; + } + }; + + @NonNull + private final TimestampedValue<Long> mUtcTime; + @Nullable + private ArrayList<String> mDebugInfo; + + public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) { + mUtcTime = Objects.requireNonNull(utcTime); + Objects.requireNonNull(utcTime.getValue()); + } + + private static NetworkTimeSuggestion createFromParcel(Parcel in) { + TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */); + NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(utcTime); + @SuppressWarnings("unchecked") + ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); + suggestion.mDebugInfo = debugInfo; + return suggestion; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeParcelable(mUtcTime, 0); + dest.writeList(mDebugInfo); + } + + @NonNull + public TimestampedValue<Long> getUtcTime() { + return mUtcTime; + } + + @NonNull + public List<String> getDebugInfo() { + return mDebugInfo == null + ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo); + } + + /** + * Associates information with the instance that can be useful for debugging / logging. The + * information is present in {@link #toString()} but is not considered for + * {@link #equals(Object)} and {@link #hashCode()}. + */ + public void addDebugInfo(String... debugInfos) { + if (mDebugInfo == null) { + mDebugInfo = new ArrayList<>(); + } + mDebugInfo.addAll(Arrays.asList(debugInfos)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + NetworkTimeSuggestion that = (NetworkTimeSuggestion) o; + return Objects.equals(mUtcTime, that.mUtcTime); + } + + @Override + public int hashCode() { + return Objects.hash(mUtcTime); + } + + @Override + public String toString() { + return "NetworkTimeSuggestion{" + + "mUtcTime=" + mUtcTime + + ", mDebugInfo=" + mDebugInfo + + '}'; + } +} diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java index 4a89a1245473..bd649f88f40a 100644 --- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java +++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java @@ -18,9 +18,10 @@ package android.app.timedetector; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import android.util.TimestampedValue; +import android.os.TimestampedValue; import java.util.ArrayList; import java.util.Collections; @@ -28,17 +29,23 @@ import java.util.List; import java.util.Objects; /** - * A time signal from a telephony source. The value can be {@code null} to indicate that the - * telephony source has entered an "un-opinionated" state and any previously sent suggestions are - * being withdrawn. When not {@code null}, the value consists of the number of milliseconds elapsed - * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number - * was established. The elapsed realtime clock is considered accurate but volatile, so time signals - * must not be persisted across device resets. + * A time suggestion from an identified telephony source. e.g. from NITZ information from a specific + * radio. + * + * <p>The time value can be {@code null} to indicate that the telephony source has entered an + * "un-opinionated" state and any previous suggestions from the source are being withdrawn. When not + * {@code null}, the value consists of the number of milliseconds elapsed since 1/1/1970 00:00:00 + * UTC and the time according to the elapsed realtime clock when that number was established. The + * elapsed realtime clock is considered accurate but volatile, so time suggestions must not be + * persisted across device resets. * * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class PhoneTimeSuggestion implements Parcelable { + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR = new Parcelable.Creator<PhoneTimeSuggestion>() { public PhoneTimeSuggestion createFromParcel(Parcel in) { @@ -85,15 +92,27 @@ public final class PhoneTimeSuggestion implements Parcelable { dest.writeList(mDebugInfo); } + /** + * Returns an identifier for the source of this suggestion. When a device has several "phones", + * i.e. sim slots or equivalent, it is used to identify which one. + */ public int getPhoneId() { return mPhoneId; } + /** + * Returns the suggestion. {@code null} means that the caller is no longer sure what time it + * is. + */ @Nullable public TimestampedValue<Long> getUtcTime() { return mUtcTime; } + /** + * Returns debug metadata for the suggestion. The information is present in {@link #toString()} + * but is not considered for {@link #equals(Object)} and {@link #hashCode()}. + */ @NonNull public List<String> getDebugInfo() { return mDebugInfo == null @@ -105,7 +124,7 @@ public final class PhoneTimeSuggestion implements Parcelable { * information is present in {@link #toString()} but is not considered for * {@link #equals(Object)} and {@link #hashCode()}. */ - public void addDebugInfo(String debugInfo) { + public void addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); } @@ -156,16 +175,19 @@ public final class PhoneTimeSuggestion implements Parcelable { * * @hide */ - public static class Builder { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class Builder { private final int mPhoneId; - private TimestampedValue<Long> mUtcTime; - private List<String> mDebugInfo; + @Nullable private TimestampedValue<Long> mUtcTime; + @Nullable private List<String> mDebugInfo; + /** Creates a builder with the specified {@code phoneId}. */ public Builder(int phoneId) { mPhoneId = phoneId; } /** Returns the builder for call chaining. */ + @NonNull public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) { if (utcTime != null) { // utcTime can be null, but the value it holds cannot. @@ -177,6 +199,7 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** Returns the builder for call chaining. */ + @NonNull public Builder addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); @@ -186,6 +209,7 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** Returns the {@link PhoneTimeSuggestion}. */ + @NonNull public PhoneTimeSuggestion build() { return new PhoneTimeSuggestion(this); } diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java index 48d5cd2d65a5..7c29f017c02b 100644 --- a/core/java/android/app/timedetector/TimeDetector.java +++ b/core/java/android/app/timedetector/TimeDetector.java @@ -18,19 +18,23 @@ package android.app.timedetector; import android.annotation.NonNull; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.os.SystemClock; +import android.os.TimestampedValue; import android.util.Log; -import android.util.TimestampedValue; /** * The interface through which system components can send signals to the TimeDetectorService. + * + * <p>This class is marked non-final for mockito. * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemService(Context.TIME_DETECTOR_SERVICE) public class TimeDetector { private static final String TAG = "timedetector.TimeDetector"; @@ -38,6 +42,7 @@ public class TimeDetector { private final ITimeDetectorService mITimeDetectorService; + /** @hide */ public TimeDetector() throws ServiceNotFoundException { mITimeDetectorService = ITimeDetectorService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE)); @@ -48,7 +53,7 @@ public class TimeDetector { * signal if better signals are available such as those that come from more reliable sources or * were determined more recently. */ - @RequiresPermission(android.Manifest.permission.SET_TIME) + @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE) public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) { if (DEBUG) { Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion); @@ -62,8 +67,10 @@ public class TimeDetector { /** * Suggests the user's manually entered current time to the detector. + * + * @hide */ - @RequiresPermission(android.Manifest.permission.SET_TIME) + @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE) public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) { if (DEBUG) { Log.d(TAG, "suggestManualTime called: " + timeSuggestion); @@ -77,6 +84,8 @@ public class TimeDetector { /** * A shared utility method to create a {@link ManualTimeSuggestion}. + * + * @hide */ public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) { TimestampedValue<Long> utcTime = @@ -85,4 +94,21 @@ public class TimeDetector { manualTimeSuggestion.addDebugInfo(why); return manualTimeSuggestion; } + + /** + * Suggests the time according to a network time source like NTP. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.SET_TIME) + public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) { + if (DEBUG) { + Log.d(TAG, "suggestNetworkTime called: " + timeSuggestion); + } + try { + mITimeDetectorService.suggestNetworkTime(timeSuggestion); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java index e8162488394c..d71ffcb9f772 100644 --- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java +++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java @@ -19,6 +19,7 @@ package android.app.timezonedetector; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -30,12 +31,27 @@ import java.util.List; import java.util.Objects; /** - * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information. + * A time zone suggestion from an identified telephony source, e.g. from MCC and NITZ information + * associated with a specific radio. + * + * <p>The time zone ID can be {@code null} to indicate that the telephony source has entered an + * "un-opinionated" state and any previous suggestions from that source are being withdrawn. + * When not {@code null}, the value consists of a suggested time zone ID and metadata that can be + * used to judge quality / certainty of the suggestion. + * + * <p>{@code matchType} must be set to {@link #MATCH_TYPE_NA} when {@code zoneId} is {@code null}, + * and one of the other {@code MATCH_TYPE_} values when it is not {@code null}. + * + * <p>{@code quality} must be set to {@link #QUALITY_NA} when {@code zoneId} is {@code null}, + * and one of the other {@code QUALITY_} values when it is not {@code null}. * * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class PhoneTimeZoneSuggestion implements Parcelable { + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public static final Creator<PhoneTimeZoneSuggestion> CREATOR = new Creator<PhoneTimeZoneSuggestion>() { @@ -58,6 +74,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { return new Builder(phoneId).addDebugInfo(debugInfo).build(); } + /** @hide */ @IntDef({ MATCH_TYPE_NA, MATCH_TYPE_NETWORK_COUNTRY_ONLY, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, MATCH_TYPE_EMULATOR_ZONE_ID, MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY }) @Retention(RetentionPolicy.SOURCE) @@ -90,6 +107,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { */ public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5; + /** @hide */ @IntDef({ QUALITY_NA, QUALITY_SINGLE_ZONE, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS }) @Retention(RetentionPolicy.SOURCE) @@ -115,7 +133,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { /** * The ID of the phone this suggestion is associated with. For multiple-sim devices this - * helps to establish origin so filtering / stickiness can be implemented. + * helps to establish source so filtering / stickiness can be implemented. */ private final int mPhoneId; @@ -123,6 +141,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { * The suggestion. {@code null} means there is no current suggestion and any previous suggestion * should be forgotten. */ + @Nullable private final String mZoneId; /** @@ -139,9 +158,10 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { private final int mQuality; /** - * Free-form debug information about how the signal was derived. Used for debug only, + * Free-form debug information about how the suggestion was derived. Used for debug only, * intentionally not used in equals(), etc. */ + @Nullable private List<String> mDebugInfo; private PhoneTimeZoneSuggestion(Builder builder) { @@ -182,25 +202,47 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { return 0; } + /** + * Returns an identifier for the source of this suggestion. When a device has several "phones", + * i.e. sim slots or equivalent, it is used to identify which one. + */ public int getPhoneId() { return mPhoneId; } + /** + * Returns the suggested time zone Olson ID, e.g. "America/Los_Angeles". {@code null} means that + * the caller is no longer sure what the current time zone is. See + * {@link PhoneTimeZoneSuggestion} for the associated {@code matchType} / {@code quality} rules. + */ @Nullable public String getZoneId() { return mZoneId; } + /** + * Returns information about how the suggestion was determined which could be used to rank + * suggestions when several are available from different sources. See + * {@link PhoneTimeZoneSuggestion} for the associated rules. + */ @MatchType public int getMatchType() { return mMatchType; } + /** + * Returns information about the likelihood of the suggested zone being correct. See + * {@link PhoneTimeZoneSuggestion} for the associated rules. + */ @Quality public int getQuality() { return mQuality; } + /** + * Returns debug metadata for the suggestion. The information is present in {@link #toString()} + * but is not considered for {@link #equals(Object)} and {@link #hashCode()}. + */ @NonNull public List<String> getDebugInfo() { return mDebugInfo == null @@ -267,36 +309,43 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { * * @hide */ - public static class Builder { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class Builder { private final int mPhoneId; - private String mZoneId; + @Nullable private String mZoneId; @MatchType private int mMatchType; @Quality private int mQuality; - private List<String> mDebugInfo; + @Nullable private List<String> mDebugInfo; public Builder(int phoneId) { mPhoneId = phoneId; } - /** Returns the builder for call chaining. */ - public Builder setZoneId(String zoneId) { + /** + * Returns the builder for call chaining. + */ + @NonNull + public Builder setZoneId(@Nullable String zoneId) { mZoneId = zoneId; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder setMatchType(@MatchType int matchType) { mMatchType = matchType; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder setQuality(@Quality int quality) { mQuality = quality; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); @@ -333,6 +382,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { } /** Returns the {@link PhoneTimeZoneSuggestion}. */ + @NonNull public PhoneTimeZoneSuggestion build() { validate(); return new PhoneTimeZoneSuggestion(this); diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java index 387a36bba608..5b5f311264e3 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetector.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java @@ -18,6 +18,7 @@ package android.app.timezonedetector; import android.annotation.NonNull; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; @@ -28,8 +29,10 @@ import android.util.Log; /** * The interface through which system components can send signals to the TimeZoneDetectorService. * + * <p>This class is non-final for mockito. * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemService(Context.TIME_ZONE_DETECTOR_SERVICE) public class TimeZoneDetector { private static final String TAG = "timezonedetector.TimeZoneDetector"; @@ -37,6 +40,7 @@ public class TimeZoneDetector { private final ITimeZoneDetectorService mITimeZoneDetectorService; + /** @hide */ public TimeZoneDetector() throws ServiceNotFoundException { mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE)); @@ -46,8 +50,11 @@ public class TimeZoneDetector { * Suggests the current time zone, determined using telephony signals, to the detector. The * detector may ignore the signal based on system settings, whether better information is * available, and so on. + * + * @hide */ - @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE) public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) { if (DEBUG) { Log.d(TAG, "suggestPhoneTimeZone called: " + timeZoneSuggestion); @@ -62,8 +69,10 @@ public class TimeZoneDetector { /** * Suggests the current time zone, determined for the user's manually information, to the * detector. The detector may ignore the signal based on system settings. + * + * @hide */ - @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE) + @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE) public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) { if (DEBUG) { Log.d(TAG, "suggestManualTimeZone called: " + timeZoneSuggestion); @@ -77,6 +86,8 @@ public class TimeZoneDetector { /** * A shared utility method to create a {@link ManualTimeZoneSuggestion}. + * + * @hide */ public static ManualTimeZoneSuggestion createManualTimeZoneSuggestion(String tzId, String why) { ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(tzId); diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java index 27abdcfbefc9..65b2775fd66b 100644 --- a/core/java/android/app/trust/TrustManager.java +++ b/core/java/android/app/trust/TrustManager.java @@ -19,7 +19,7 @@ package android.app.trust; import android.Manifest; import android.annotation.RequiresPermission; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.hardware.biometrics.BiometricSourceType; import android.os.Handler; diff --git a/core/java/android/app/usage/ConfigurationStats.java b/core/java/android/app/usage/ConfigurationStats.java index da3b76972ced..8a7107de8363 100644 --- a/core/java/android/app/usage/ConfigurationStats.java +++ b/core/java/android/app/usage/ConfigurationStats.java @@ -15,7 +15,7 @@ */ package android.app.usage; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Configuration; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 6bade901826a..9c4a8f4fbe27 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,19 +16,23 @@ package android.app.usage; -import static com.android.internal.util.Preconditions.checkNotNull; - +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.usage.NetworkStats.Bucket; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkTemplate; +import android.net.netstats.provider.AbstractNetworkStatsProvider; +import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProviderWrapper; import android.os.Binder; import android.os.Handler; import android.os.Looper; @@ -42,6 +46,8 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import java.util.Objects; + /** * Provides access to network usage history and statistics. Usage data is collected in * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. @@ -418,7 +424,7 @@ public class NetworkStatsManager { /** @hide */ public void registerUsageCallback(NetworkTemplate template, int networkType, long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { - checkNotNull(callback, "UsageCallback cannot be null"); + Objects.requireNonNull(callback, "UsageCallback cannot be null"); final Looper looper; if (handler == null) { @@ -519,6 +525,34 @@ public class NetworkStatsManager { private DataUsageRequest request; } + /** + * Registers a custom provider of {@link android.net.NetworkStats} to combine the network + * statistics that cannot be seen by the kernel to system. To unregister, invoke + * {@link NetworkStatsProviderCallback#unregister()}. + * + * @param tag a human readable identifier of the custom network stats provider. + * @param provider a custom implementation of {@link AbstractNetworkStatsProvider} that needs to + * be registered to the system. + * @return a {@link NetworkStatsProviderCallback}, which can be used to report events to the + * system. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( + @NonNull String tag, + @NonNull AbstractNetworkStatsProvider provider) { + try { + final NetworkStatsProviderWrapper wrapper = new NetworkStatsProviderWrapper(provider); + return new NetworkStatsProviderCallback( + mService.registerNetworkStatsProvider(tag, wrapper)); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + // Unreachable code, but compiler doesn't know about it. + return null; + } + private static NetworkTemplate createTemplate(int networkType, String subscriberId) { final NetworkTemplate template; switch (networkType) { diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 84c68552c40a..c646fc69702d 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -18,7 +18,7 @@ package android.app.usage; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Configuration; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java index 2c021cc42cb5..3550ebd24026 100644 --- a/core/java/android/app/usage/UsageStats.java +++ b/core/java/android/app/usage/UsageStats.java @@ -29,7 +29,7 @@ import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP; import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.Parcel; diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 92e1b30793c9..102a08d17deb 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -23,9 +23,9 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.Build; diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java index f003d4bea028..f61d35bc7d33 100644 --- a/core/java/android/appwidget/AppWidgetHost.java +++ b/core/java/android/appwidget/AppWidgetHost.java @@ -18,8 +18,8 @@ package android.appwidget; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.IntentSender; diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 85f0e2342412..09d56ec70e56 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -16,9 +16,9 @@ package android.appwidget; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.ActivityOptions; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index dbc1c199cb4d..6dea1c69ce86 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -23,9 +23,9 @@ import android.annotation.RequiresFeature; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.IServiceConnection; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 2faa9007fc29..130a20dfb07b 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -18,8 +18,8 @@ package android.appwidget; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 64df0e84f6dc..d8c653c6d0d5 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -24,7 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; import android.os.Build; diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java index c6957e14116b..8993de0939e6 100755 --- a/core/java/android/bluetooth/BluetoothA2dpSink.java +++ b/core/java/android/bluetooth/BluetoothA2dpSink.java @@ -21,7 +21,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; import android.os.IBinder; diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 291d1d99fdc9..bd0a39c06b26 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -25,7 +25,6 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.bluetooth.BluetoothProfile.ConnectionPolicy; import android.bluetooth.le.BluetoothLeAdvertiser; @@ -36,6 +35,7 @@ import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; @@ -1222,6 +1222,7 @@ public final class BluetoothAdapter { if (mService != null) { return mService.factoryReset(); } + Log.e(TAG, "factoryReset(): IBluetooth Service is null"); SystemProperties.set("persist.bluetooth.factoryreset", "true"); } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1239,7 +1240,7 @@ public final class BluetoothAdapter { */ @UnsupportedAppUsage @RequiresPermission(Manifest.permission.BLUETOOTH) - public @NonNull ParcelUuid[] getUuids() { + public @Nullable ParcelUuid[] getUuids() { if (getState() != STATE_ON) { return null; } @@ -2670,6 +2671,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.PAN) { BluetoothPan pan = new BluetoothPan(context, listener); return true; + } else if (profile == BluetoothProfile.PBAP) { + BluetoothPbap pbap = new BluetoothPbap(context, listener); + return true; } else if (profile == BluetoothProfile.HEALTH) { Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated"); return false; @@ -2742,6 +2746,10 @@ public final class BluetoothAdapter { BluetoothPan pan = (BluetoothPan) proxy; pan.close(); break; + case BluetoothProfile.PBAP: + BluetoothPbap pbap = (BluetoothPbap) proxy; + pbap.close(); + break; case BluetoothProfile.GATT: BluetoothGatt gatt = (BluetoothGatt) proxy; gatt.close(); diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java index 260e2fb1b80c..905b0ceec4ee 100755 --- a/core/java/android/bluetooth/BluetoothClass.java +++ b/core/java/android/bluetooth/BluetoothClass.java @@ -17,7 +17,7 @@ package android.bluetooth; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java index 08d0797997b5..93e76fa5ba7d 100644 --- a/core/java/android/bluetooth/BluetoothCodecConfig.java +++ b/core/java/android/bluetooth/BluetoothCodecConfig.java @@ -19,7 +19,7 @@ package android.bluetooth; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 323c7d172033..9fe4dd66b874 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -24,7 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; import android.os.Parcel; diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index d616b8f92d3a..f877f04626da 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -16,7 +16,7 @@ package android.bluetooth; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Handler; import android.os.ParcelUuid; diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java index edacf3e0b706..7066f470aa96 100644 --- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java +++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java @@ -15,7 +15,7 @@ */ package android.bluetooth; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.ParcelUuid; import android.os.Parcelable; diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java index 0783cd2b73cc..7cc2d6bc53fb 100644 --- a/core/java/android/bluetooth/BluetoothGattDescriptor.java +++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java @@ -16,7 +16,7 @@ package android.bluetooth; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.ParcelUuid; import android.os.Parcelable; diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java index c20faf9db698..13d6d7021ec8 100644 --- a/core/java/android/bluetooth/BluetoothGattService.java +++ b/core/java/android/bluetooth/BluetoothGattService.java @@ -15,7 +15,7 @@ */ package android.bluetooth; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.ParcelUuid; import android.os.Parcelable; diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 0955b103a8e8..1ba2bb5e31ad 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -23,7 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.os.Binder; diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java index 7ee29ff1c50b..6de1ffb6344e 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -19,7 +19,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; import android.os.Bundle; diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java index 7165dd56a213..d1a096e605dd 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java @@ -16,7 +16,7 @@ package android.bluetooth; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java index a65162ad5d89..38498bc147b2 100644 --- a/core/java/android/bluetooth/BluetoothHearingAid.java +++ b/core/java/android/bluetooth/BluetoothHearingAid.java @@ -23,7 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; import android.os.IBinder; diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java index e9b0be2c4cd6..a923be62fbce 100644 --- a/core/java/android/bluetooth/BluetoothHidDevice.java +++ b/core/java/android/bluetooth/BluetoothHidDevice.java @@ -16,8 +16,12 @@ package android.bluetooth; +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; import android.os.IBinder; @@ -36,6 +40,7 @@ import java.util.concurrent.Executor; */ public final class BluetoothHidDevice implements BluetoothProfile { private static final String TAG = BluetoothHidDevice.class.getSimpleName(); + private static final boolean DBG = false; /** * Intent used to broadcast the change in connection state of the Input Host profile. @@ -682,4 +687,62 @@ public final class BluetoothHidDevice implements BluetoothProfile { return result; } + + /** + * Connects Hid Device if connectionPolicy is {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED} + * and disconnects Hid device if connectionPolicy is + * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}. + * + * <p> The device should already be paired. + * Connection policy can be one of: + * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, + * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, + * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} + * + * @param device Paired bluetooth device + * @param connectionPolicy determines whether hid device should be connected or disconnected + * @return true if hid device is connected or disconnected, false otherwise + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean setConnectionPolicy(@NonNull BluetoothDevice device, + @ConnectionPolicy int connectionPolicy) { + log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); + try { + final IBluetoothHidDevice service = getService(); + if (service != null && isEnabled() + && isValidDevice(device)) { + if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + if (DBG) { + Log.d(TAG, msg); + } + } } diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java index 8f5cdf01f572..c1233b800a51 100644 --- a/core/java/android/bluetooth/BluetoothHidHost.java +++ b/core/java/android/bluetooth/BluetoothHidHost.java @@ -17,9 +17,12 @@ package android.bluetooth; import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; @@ -43,6 +46,7 @@ import java.util.List; * * @hide */ +@SystemApi public final class BluetoothHidHost implements BluetoothProfile { private static final String TAG = "BluetoothHidHost"; private static final boolean DBG = true; @@ -66,6 +70,7 @@ public final class BluetoothHidHost implements BluetoothProfile { * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to * receive. */ + @SuppressLint("ActionValue") @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"; @@ -325,7 +330,7 @@ public final class BluetoothHidHost implements BluetoothProfile { * {@inheritDoc} */ @Override - public List<BluetoothDevice> getConnectedDevices() { + public @NonNull List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothHidHost service = getService(); if (service != null && isEnabled()) { @@ -342,6 +347,8 @@ public final class BluetoothHidHost implements BluetoothProfile { /** * {@inheritDoc} + * + * @hide */ @Override public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { @@ -363,7 +370,7 @@ public final class BluetoothHidHost implements BluetoothProfile { * {@inheritDoc} */ @Override - public int getConnectionState(BluetoothDevice device) { + public int getConnectionState(@Nullable BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); final IBluetoothHidHost service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -409,7 +416,7 @@ public final class BluetoothHidHost implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) - public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { + public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothHidHost service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -457,7 +464,7 @@ public final class BluetoothHidHost implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH) - public int getConnectionPolicy(BluetoothDevice device) { + public int getConnectionPolicy(@Nullable BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothHidHost service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java index 979dfd4e3ba5..467470674286 100644 --- a/core/java/android/bluetooth/BluetoothMap.java +++ b/core/java/android/bluetooth/BluetoothMap.java @@ -17,9 +17,12 @@ package android.bluetooth; import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; import android.os.IBinder; @@ -35,21 +38,35 @@ import java.util.List; * * @hide */ +@SystemApi public final class BluetoothMap implements BluetoothProfile { private static final String TAG = "BluetoothMap"; private static final boolean DBG = true; private static final boolean VDBG = false; + /** @hide */ + @SuppressLint("ActionValue") + @SystemApi public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED"; - /** There was an error trying to obtain the state */ + /** + * There was an error trying to obtain the state + * + * @hide + */ public static final int STATE_ERROR = -1; + /** @hide */ public static final int RESULT_FAILURE = 0; + /** @hide */ public static final int RESULT_SUCCESS = 1; - /** Connection canceled before completion. */ + /** + * Connection canceled before completion. + * + * @hide + */ public static final int RESULT_CANCELED = 2; private BluetoothAdapter mAdapter; @@ -71,6 +88,7 @@ public final class BluetoothMap implements BluetoothProfile { mProfileConnector.connect(context, listener); } + @SuppressLint("GenericException") protected void finalize() throws Throwable { try { close(); @@ -84,6 +102,8 @@ public final class BluetoothMap implements BluetoothProfile { * Other public functions of BluetoothMap will return default error * results once close() has been called. Multiple invocations of close() * are ok. + * + * @hide */ public synchronized void close() { mProfileConnector.disconnect(); @@ -98,6 +118,8 @@ public final class BluetoothMap implements BluetoothProfile { * * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not * connected to the Map service. + * + * @hide */ public int getState() { if (VDBG) log("getState()"); @@ -120,6 +142,8 @@ public final class BluetoothMap implements BluetoothProfile { * * @return The remote Bluetooth device, or null if not in connected or connecting state, or if * this proxy object is not connected to the Map service. + * + * @hide */ public BluetoothDevice getClient() { if (VDBG) log("getClient()"); @@ -141,6 +165,8 @@ public final class BluetoothMap implements BluetoothProfile { * Returns true if the specified Bluetooth device is connected. * Returns false if not connected, or if this proxy object is not * currently connected to the Map service. + * + * @hide */ public boolean isConnected(BluetoothDevice device) { if (VDBG) log("isConnected(" + device + ")"); @@ -161,6 +187,8 @@ public final class BluetoothMap implements BluetoothProfile { /** * Initiate connection. Initiation of outgoing connections is not * supported for MAP server. + * + * @hide */ public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")" + "not supported for MAPS"); @@ -172,6 +200,8 @@ public final class BluetoothMap implements BluetoothProfile { * * @param device Remote Bluetooth Device * @return false on error, true otherwise + * + * @hide */ @UnsupportedAppUsage public boolean disconnect(BluetoothDevice device) { @@ -196,6 +226,8 @@ public final class BluetoothMap implements BluetoothProfile { * devices. It tries to err on the side of false positives. * * @return True if this device might support Map. + * + * @hide */ public static boolean doesClassMatchSink(BluetoothClass btClass) { // TODO optimize the rule @@ -214,8 +246,11 @@ public final class BluetoothMap implements BluetoothProfile { * Get the list of connected devices. Currently at most one. * * @return list of connected devices + * + * @hide */ - public List<BluetoothDevice> getConnectedDevices() { + @SystemApi + public @NonNull List<BluetoothDevice> getConnectedDevices() { if (DBG) log("getConnectedDevices()"); final IBluetoothMap service = getService(); if (service != null && isEnabled()) { @@ -234,6 +269,8 @@ public final class BluetoothMap implements BluetoothProfile { * Get the list of devices matching specified states. Currently at most one. * * @return list of matching devices + * + * @hide */ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (DBG) log("getDevicesMatchingStates()"); @@ -254,6 +291,8 @@ public final class BluetoothMap implements BluetoothProfile { * Get connection state of device * * @return device connection state + * + * @hide */ public int getConnectionState(BluetoothDevice device) { if (DBG) log("getConnectionState(" + device + ")"); @@ -301,7 +340,7 @@ public final class BluetoothMap implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) - public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { + public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothMap service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -349,7 +388,7 @@ public final class BluetoothMap implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH) - public int getConnectionPolicy(BluetoothDevice device) { + public int getConnectionPolicy(@Nullable BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothMap service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java index 0ec473c85adc..0aa5aac5d8f6 100644 --- a/core/java/android/bluetooth/BluetoothMapClient.java +++ b/core/java/android/bluetooth/BluetoothMapClient.java @@ -19,8 +19,8 @@ package android.bluetooth; import android.Manifest; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.Uri; import android.os.Binder; diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index 4e9762737c07..ec63fd058b16 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -16,18 +16,21 @@ package android.bluetooth; +import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.util.CloseGuard; import android.util.Log; import java.lang.annotation.Retention; @@ -48,10 +51,11 @@ import java.util.List; * @hide */ @SystemApi -public final class BluetoothPan implements BluetoothProfile { +public final class BluetoothPan implements BluetoothProfile, AutoCloseable { private static final String TAG = "BluetoothPan"; private static final boolean DBG = true; private static final boolean VDBG = false; + private CloseGuard mCloseGuard; /** * Intent used to broadcast the change in connection state of the Pan @@ -164,10 +168,15 @@ public final class BluetoothPan implements BluetoothProfile { mAdapter = BluetoothAdapter.getDefaultAdapter(); mContext = context; mProfileConnector.connect(context, listener); + mCloseGuard = new CloseGuard(); + mCloseGuard.open("close"); } - @UnsupportedAppUsage - /*package*/ void close() { + /** + * Closes the connection to the service and unregisters callbacks + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public void close() { if (VDBG) log("close()"); mProfileConnector.disconnect(); } @@ -176,8 +185,11 @@ public final class BluetoothPan implements BluetoothProfile { return mProfileConnector.getService(); } - + @RequiresPermission(Manifest.permission.BLUETOOTH) protected void finalize() { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } close(); } @@ -256,6 +268,41 @@ public final class BluetoothPan implements BluetoothProfile { } /** + * Set connection policy of the profile + * + * <p> The device should already be paired. + * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, + * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + * + * @param device Paired bluetooth device + * @param connectionPolicy is the connection policy to set to for this profile + * @return true if connectionPolicy is set, false on error + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean setConnectionPolicy(@NonNull BluetoothDevice device, + @ConnectionPolicy int connectionPolicy) { + if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); + try { + final IBluetoothPan service = getService(); + if (service != null && isEnabled() + && isValidDevice(device)) { + if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** * {@inheritDoc} */ @Override @@ -279,6 +326,7 @@ public final class BluetoothPan implements BluetoothProfile { * @hide */ @Override + @RequiresPermission(Manifest.permission.BLUETOOTH) public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); final IBluetoothPan service = getService(); @@ -298,6 +346,7 @@ public final class BluetoothPan implements BluetoothProfile { * {@inheritDoc} */ @Override + @RequiresPermission(Manifest.permission.BLUETOOTH) public int getConnectionState(@Nullable BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); final IBluetoothPan service = getService(); @@ -318,6 +367,7 @@ public final class BluetoothPan implements BluetoothProfile { * * @param value is whether to enable or disable bluetooth tethering */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public void setBluetoothTethering(boolean value) { String pkgName = mContext.getOpPackageName(); if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName); @@ -336,6 +386,7 @@ public final class BluetoothPan implements BluetoothProfile { * * @return true if tethering is on, false if not or some error occurred */ + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isTetheringOn() { if (VDBG) log("isTetheringOn()"); final IBluetoothPan service = getService(); diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index df0289643ee0..e07ca521e77d 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -16,11 +16,14 @@ package android.bluetooth; +import android.Manifest; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -271,6 +274,42 @@ public class BluetoothPbap implements BluetoothProfile { } /** + * Pbap does not store connection policy, so this function only disconnects pbap if + * connectionPolicy is {@link #CONNECTION_POLICY_FORBIDDEN}. + * + * <p> The device should already be paired. + * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, + * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + * + * @param device Paired bluetooth device + * @param connectionPolicy determines whether to disconnect the device + * @return true if pbap is successfully disconnected, false otherwise + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean setConnectionPolicy(@NonNull BluetoothDevice device, + @ConnectionPolicy int connectionPolicy) { + if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); + try { + final IBluetoothPbap service = mService; + if (service != null && isEnabled() + && isValidDevice(device)) { + if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** * Disconnects the current Pbap client (PCE). Currently this call blocks, * it may soon be made asynchronous. Returns false if this proxy object is * not currently connected to the Pbap service. diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 097a3677ac4b..7538df8bbe5f 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -22,7 +22,7 @@ import android.annotation.IntDef; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -146,7 +146,7 @@ public interface BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi int A2DP_SINK = 11; /** @@ -154,7 +154,7 @@ public interface BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi int AVRCP_CONTROLLER = 12; /** @@ -169,6 +169,7 @@ public interface BluetoothProfile { * * @hide */ + @SystemApi int HEADSET_CLIENT = 16; /** @@ -176,6 +177,7 @@ public interface BluetoothProfile { * * @hide */ + @SystemApi int PBAP_CLIENT = 17; /** diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java index 9b4dabcdcfdc..8bf1b588c89a 100644 --- a/core/java/android/bluetooth/BluetoothSap.java +++ b/core/java/android/bluetooth/BluetoothSap.java @@ -19,7 +19,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; import android.os.IBinder; diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java index 3a23808f3617..88c186c88aaf 100644 --- a/core/java/android/bluetooth/BluetoothServerSocket.java +++ b/core/java/android/bluetooth/BluetoothServerSocket.java @@ -16,7 +16,7 @@ package android.bluetooth; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.ParcelUuid; import android.util.Log; diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index 760166bfcc5d..f77436965537 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -16,7 +16,7 @@ package android.bluetooth; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.LocalSocket; import android.os.ParcelFileDescriptor; import android.os.ParcelUuid; diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index 7e96c23af4b9..e274af1b5c5d 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -19,7 +19,7 @@ package android.bluetooth; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelUuid; import java.nio.ByteBuffer; diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java index 97e3f5221c72..c0c1aa1634ff 100644 --- a/core/java/android/bluetooth/le/ScanRecord.java +++ b/core/java/android/bluetooth/le/ScanRecord.java @@ -18,8 +18,8 @@ package android.bluetooth.le; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothUuid; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelUuid; import android.util.ArrayMap; import android.util.Log; diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java index e4114c66bac7..489d125a1bf6 100644 --- a/core/java/android/companion/AssociationRequest.java +++ b/core/java/android/companion/AssociationRequest.java @@ -18,7 +18,7 @@ package android.companion; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.provider.OneTimeUseBuilder; diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java index fe0123c56e57..2649fbee4246 100644 --- a/core/java/android/companion/BluetoothDeviceFilter.java +++ b/core/java/android/companion/BluetoothDeviceFilter.java @@ -25,8 +25,8 @@ import static android.companion.BluetoothDeviceFilterUtils.patternToString; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.ParcelUuid; import android.provider.OneTimeUseBuilder; diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java index 0f67f6b50251..24be45cb20fe 100644 --- a/core/java/android/companion/BluetoothDeviceFilterUtils.java +++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java @@ -21,9 +21,9 @@ import static android.text.TextUtils.firstNotEmpty; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; import android.bluetooth.le.ScanFilter; +import android.compat.annotation.UnsupportedAppUsage; import android.net.wifi.ScanResult; import android.os.ParcelUuid; import android.os.Parcelable; diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java index 2701619112c5..730bc60e331c 100644 --- a/core/java/android/companion/BluetoothLeDeviceFilter.java +++ b/core/java/android/companion/BluetoothLeDeviceFilter.java @@ -25,11 +25,11 @@ import static com.android.internal.util.Preconditions.checkState; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.provider.OneTimeUseBuilder; import android.text.TextUtils; diff --git a/core/java/android/companion/DeviceFilter.java b/core/java/android/companion/DeviceFilter.java index dc7cf82613e6..c9cb072904b4 100644 --- a/core/java/android/companion/DeviceFilter.java +++ b/core/java/android/companion/DeviceFilter.java @@ -19,7 +19,7 @@ package android.companion; import android.annotation.IntDef; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcelable; import java.lang.annotation.Retention; diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java index bb7d5e49ccfb..14c3387d47dc 100644 --- a/core/java/android/content/AsyncTaskLoader.java +++ b/core/java/android/content/AsyncTaskLoader.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.AsyncTask; import android.os.Handler; import android.os.OperationCanceledException; diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index f73a376dfc69..1d4d30d87560 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -18,11 +18,11 @@ package android.content; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.IActivityManager; import android.app.QueuedWork; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.IBinder; diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 88e2c220bb8d..5c6728348893 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -21,7 +21,7 @@ import static android.content.ContentResolver.SCHEME_ANDROID_RESOURCE; import static android.content.ContentResolver.SCHEME_CONTENT; import static android.content.ContentResolver.SCHEME_FILE; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.net.Uri; diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index dc1c700f5d08..dec9589981c6 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -19,7 +19,7 @@ package android.content; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java index 18147b572125..e955c2df2881 100644 --- a/core/java/android/content/ComponentName.java +++ b/core/java/android/content/ComponentName.java @@ -18,7 +18,7 @@ package android.content; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 7cdd2683905f..137faea5121f 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -26,8 +26,8 @@ import static android.os.Trace.TRACE_TAG_DATABASE; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.AppOpsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.PathPermission; import android.content.pm.ProviderInfo; import android.content.res.AssetFileDescriptor; diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java index 93bf5188705c..db8aa40978b3 100644 --- a/core/java/android/content/ContentProviderClient.java +++ b/core/java/android/content/ContentProviderClient.java @@ -22,7 +22,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.database.CrossProcessCursorWrapper; import android.database.Cursor; diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index 994833866f40..234f567f2ad2 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -17,7 +17,7 @@ package android.content; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.database.BulkCursorDescriptor; import android.database.BulkCursorToCursorAdaptor; diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index c201e4d2a129..e401f2aeb23a 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.Cursor; import android.net.Uri; import android.os.Parcel; diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 0a1bc85202ff..a50831fd0193 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -25,12 +25,12 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.UriGrantsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java index eafeed220050..76d37fcd2ce9 100644 --- a/core/java/android/content/ContentValues.java +++ b/core/java/android/content/ContentValues.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 902c6b9dd36d..cd4af968ebfc 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -30,14 +30,15 @@ import android.annotation.StringDef; import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.StyleableRes; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.IApplicationThread; import android.app.IServiceConnection; import android.app.VrManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -3827,6 +3828,7 @@ public abstract class Context { */ @SystemApi @TestApi + @SuppressLint("ServiceName") public static final String STATUS_BAR_SERVICE = "statusbar"; /** @@ -3851,10 +3853,12 @@ public abstract class Context { /** * Use with {@link android.os.ServiceManager.getService()} to retrieve a - * {@link NetworkStackClient} IBinder for communicating with the network stack + * {@link INetworkStackConnector} IBinder for communicating with the network stack * @hide * @see NetworkStackClient */ + @SystemApi + @TestApi public static final String NETWORK_STACK_SERVICE = "network_stack"; /** @@ -3918,6 +3922,8 @@ public abstract class Context { */ public static final String NETWORK_STATS_SERVICE = "netstats"; /** {@hide} */ + @SystemApi + @SuppressLint("ServiceName") public static final String NETWORK_POLICY_SERVICE = "netpolicy"; /** {@hide} */ public static final String NETWORK_WATCHLIST_SERVICE = "network_watchlist"; @@ -4227,6 +4233,7 @@ public abstract class Context { * @see #getSystemService(String) */ @TestApi + @SuppressLint("ServiceName") // TODO: This should be renamed to CONTENT_CAPTURE_SERVICE public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; /** diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 877557f4f590..72cc021b6ea4 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -21,9 +21,9 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.IApplicationThread; import android.app.IServiceConnection; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; diff --git a/core/java/android/content/CursorEntityIterator.java b/core/java/android/content/CursorEntityIterator.java index 2c630d29621b..952366d1cd75 100644 --- a/core/java/android/content/CursorEntityIterator.java +++ b/core/java/android/content/CursorEntityIterator.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.Cursor; import android.os.RemoteException; diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java index 4ccafab741d8..4ff5ccabbcb7 100644 --- a/core/java/android/content/CursorLoader.java +++ b/core/java/android/content/CursorLoader.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.Cursor; import android.net.Uri; import android.os.CancellationSignal; diff --git a/core/java/android/content/Entity.java b/core/java/android/content/Entity.java index ff4f15006280..13137c48e7f2 100644 --- a/core/java/android/content/Entity.java +++ b/core/java/android/content/Entity.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index 0427c2f52415..92df7eea9216 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -17,7 +17,7 @@ package android.content; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.net.Uri; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index a6867ff209e4..9cba7aab3c87 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -28,8 +28,8 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.AppGlobals; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; @@ -4011,6 +4011,7 @@ public class Intent implements Parcelable, Cloneable { * <p> * @see #EXTRA_SIM_STATE * @see #EXTRA_SIM_LOCKED_REASON + * @see #EXTRA_REBROADCAST_ON_UNLOCK * * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or * {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} @@ -4187,6 +4188,18 @@ public class Intent implements Parcelable, Cloneable { public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED"; /** + * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for indicating whether this broadcast + * is a rebroadcast on unlock. Defaults to {@code false} if not specified. + * + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or + * {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String EXTRA_REBROADCAST_ON_UNLOCK = "rebroadcastOnUnlock"; + + /** * Broadcast Action: indicate that the phone service state has changed. * The intent will have the following extra values:</p> * <p> diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 099dea29eaf7..4d0ecff38806 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -18,7 +18,7 @@ package android.content; import android.annotation.IntDef; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index ec0bac486c65..f40dc298d560 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -16,14 +16,14 @@ package android.content; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; -import android.os.RemoteException; import android.os.Handler; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; import android.os.UserHandle; import android.util.AndroidException; diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java index bbdab048207b..885eb708d92c 100644 --- a/core/java/android/content/RestrictionsManager.java +++ b/core/java/android/content/RestrictionsManager.java @@ -17,9 +17,9 @@ package android.content; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; diff --git a/core/java/android/content/SearchRecentSuggestionsProvider.java b/core/java/android/content/SearchRecentSuggestionsProvider.java index 8ee7b9e403b4..fc3ddf6148de 100644 --- a/core/java/android/content/SearchRecentSuggestionsProvider.java +++ b/core/java/android/content/SearchRecentSuggestionsProvider.java @@ -16,8 +16,8 @@ package android.content; -import android.annotation.UnsupportedAppUsage; import android.app.SearchManager; +import android.compat.annotation.UnsupportedAppUsage; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java index 8c8fe5a06888..7bcdbfd1085c 100644 --- a/core/java/android/content/SyncAdapterType.java +++ b/core/java/android/content/SyncAdapterType.java @@ -17,11 +17,11 @@ package android.content; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; -import android.text.TextUtils; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; /** * Value type that represents a SyncAdapterType. This object overrides {@link #equals} and diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java index d4e52175f9b5..58445a7f9242 100644 --- a/core/java/android/content/SyncAdaptersCache.java +++ b/core/java/android/content/SyncAdaptersCache.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.RegisteredServicesCache; import android.content.pm.XmlSerializerAndParser; import android.content.res.Resources; @@ -29,8 +29,8 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.util.ArrayList; diff --git a/core/java/android/content/SyncContext.java b/core/java/android/content/SyncContext.java index 50d1dc96fc0a..4a9f66c474db 100644 --- a/core/java/android/content/SyncContext.java +++ b/core/java/android/content/SyncContext.java @@ -16,10 +16,10 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; -import android.os.IBinder; public class SyncContext { private ISyncContext mSyncContext; diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java index d3f2eed8126f..017a92b1e8bb 100644 --- a/core/java/android/content/SyncInfo.java +++ b/core/java/android/content/SyncInfo.java @@ -17,7 +17,7 @@ package android.content; import android.accounts.Account; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java index 5f1f18016e0d..9e568a40e0ee 100644 --- a/core/java/android/content/SyncRequest.java +++ b/core/java/android/content/SyncRequest.java @@ -17,7 +17,7 @@ package android.content; import android.accounts.Account; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.Parcel; diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java index 3f6451577258..620fdb7deec4 100644 --- a/core/java/android/content/SyncStatusInfo.java +++ b/core/java/android/content/SyncStatusInfo.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; diff --git a/core/java/android/content/UndoManager.java b/core/java/android/content/UndoManager.java index f9c58d624a2f..ed9cd86927ae 100644 --- a/core/java/android/content/UndoManager.java +++ b/core/java/android/content/UndoManager.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.text.TextUtils; import android.util.ArrayMap; diff --git a/core/java/android/content/UndoOperation.java b/core/java/android/content/UndoOperation.java index a425486e5739..235d72123ff6 100644 --- a/core/java/android/content/UndoOperation.java +++ b/core/java/android/content/UndoOperation.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java index 208bc01aef9d..7fa48f0e9a78 100644 --- a/core/java/android/content/UriMatcher.java +++ b/core/java/android/content/UriMatcher.java @@ -16,7 +16,7 @@ package android.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import java.util.ArrayList; diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java index 1a78f793c008..a3487be3cb81 100644 --- a/core/java/android/content/om/OverlayInfo.java +++ b/core/java/android/content/om/OverlayInfo.java @@ -20,8 +20,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 95e5f6b322ad..43dd1f451ab7 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -18,7 +18,7 @@ package android.content.pm; import android.annotation.IntDef; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.res.Configuration; diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 0ea1845b6c2d..49d22015c432 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -22,7 +22,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java index 4178309450bd..5d1a08cf5de0 100644 --- a/core/java/android/content/pm/BaseParceledListSlice.java +++ b/core/java/android/content/pm/BaseParceledListSlice.java @@ -16,7 +16,7 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java index 29612c25d0cd..988b280d78ef 100644 --- a/core/java/android/content/pm/ComponentInfo.java +++ b/core/java/android/content/pm/ComponentInfo.java @@ -16,7 +16,7 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.graphics.drawable.Drawable; import android.os.Parcel; diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java index 1451431b7852..67deb82f1fbb 100644 --- a/core/java/android/content/pm/LauncherActivityInfo.java +++ b/core/java/android/content/pm/LauncherActivityInfo.java @@ -16,7 +16,7 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 3933e81c732a..ac8eab786dcf 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -25,10 +25,10 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index d6fb28f694fd..f4d4a8d8e1c5 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -17,7 +17,7 @@ package android.content.pm; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java index f5442ec48d19..6743a3f86944 100644 --- a/core/java/android/content/pm/PackageInfoLite.java +++ b/core/java/android/content/pm/PackageInfoLite.java @@ -16,7 +16,7 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 1099d8bdc7dd..78db3d82ce93 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -26,9 +26,9 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.AppGlobals; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.DeleteFlags; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 81670cd0d2b8..0ae00fb68d84 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -29,7 +29,6 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.StringRes; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.annotation.XmlRes; import android.app.ActivityManager; @@ -38,6 +37,7 @@ import android.app.PackageDeleteObserver; import android.app.PackageInstallObserver; import android.app.admin.DevicePolicyManager; import android.app.usage.StorageStatsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 812ae93f0641..0e610169ffa6 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -47,11 +47,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.apex.ApexInfo; import android.app.ActivityTaskManager; import android.app.ActivityThread; import android.app.ResourcesManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java index b0fecfac2471..7c1252737f09 100644 --- a/core/java/android/content/pm/PackageStats.java +++ b/core/java/android/content/pm/PackageStats.java @@ -16,8 +16,8 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; import android.app.usage.StorageStatsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 249b6919fc28..d1e113293251 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -27,7 +27,7 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.BaseBundle; import android.os.Debug; import android.os.PersistableBundle; diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java index dccc52494f59..73119e05095b 100644 --- a/core/java/android/content/pm/ParceledListSlice.java +++ b/core/java/android/content/pm/ParceledListSlice.java @@ -16,7 +16,7 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index c77c53f387e2..89a1c6ad9241 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -22,7 +22,7 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index 23fbefb73c50..bd909c7a3f59 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -17,7 +17,7 @@ package android.content.pm; import android.Manifest; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -43,11 +43,11 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; +import libcore.io.IoUtils; + import com.google.android.collect.Lists; import com.google.android.collect.Maps; -import libcore.io.IoUtils; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index 1734182b3a9a..7755fe3051e0 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -17,7 +17,7 @@ package android.content.pm; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.IntentFilter; import android.graphics.drawable.Drawable; diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 58aacc2c36c7..e14bcf6e5bed 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -20,11 +20,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.app.Notification; import android.app.Person; import android.app.TaskStackBuilder; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index f85179942938..dde8865467a1 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -22,9 +22,9 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.app.usage.UsageStatsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java index 25a4dca4d815..3b84ae775ad1 100644 --- a/core/java/android/content/pm/Signature.java +++ b/core/java/android/content/pm/Signature.java @@ -16,7 +16,7 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 2b1b32ed3df2..caf095884db2 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -16,10 +16,9 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; diff --git a/core/java/android/content/pm/VerifierInfo.java b/core/java/android/content/pm/VerifierInfo.java index 224ca628cf27..5f8855572ef0 100644 --- a/core/java/android/content/pm/VerifierInfo.java +++ b/core/java/android/content/pm/VerifierInfo.java @@ -16,7 +16,7 @@ package android.content.pm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/pm/XmlSerializerAndParser.java b/core/java/android/content/pm/XmlSerializerAndParser.java index 6d24800edb07..5dce83902f78 100644 --- a/core/java/android/content/pm/XmlSerializerAndParser.java +++ b/core/java/android/content/pm/XmlSerializerAndParser.java @@ -16,11 +16,12 @@ package android.content.pm; -import org.xmlpull.v1.XmlSerializer; +import android.compat.annotation.UnsupportedAppUsage; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; -import android.annotation.UnsupportedAppUsage; import java.io.IOException; /** @hide */ diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java index 69462ab99483..baa3e849a194 100644 --- a/core/java/android/content/res/ApkAssets.java +++ b/core/java/android/content/res/ApkAssets.java @@ -16,7 +16,7 @@ package android.content.res; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java index 2ba55798d665..e93ec00468f5 100644 --- a/core/java/android/content/res/AssetFileDescriptor.java +++ b/core/java/android/content/res/AssetFileDescriptor.java @@ -16,7 +16,7 @@ package android.content.res; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.Parcel; import android.os.ParcelFileDescriptor; diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index e5ef67b7d4bd..a70eff9fc810 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -24,7 +24,7 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.res.Configuration.NativeConfig; import android.os.ParcelFileDescriptor; diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index b5b097b33ef3..f23c802d98e2 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -19,9 +19,18 @@ package android.content.res; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.Resources.Theme; import android.graphics.Color; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.Log; +import android.util.MathUtils; +import android.util.SparseArray; +import android.util.StateSet; +import android.util.Xml; import com.android.internal.R; import com.android.internal.util.ArrayUtils; @@ -30,16 +39,6 @@ import com.android.internal.util.GrowingArrayUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import android.annotation.UnsupportedAppUsage; -import android.util.AttributeSet; -import android.util.Log; -import android.util.MathUtils; -import android.util.SparseArray; -import android.util.StateSet; -import android.util.Xml; -import android.os.Parcel; -import android.os.Parcelable; - import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Arrays; diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index f3b7553577ca..c66c70a20729 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -16,7 +16,7 @@ package android.content.res; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ApplicationInfo; import android.graphics.Canvas; import android.graphics.PointF; diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index e40e56606080..cec6382cf559 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -45,8 +45,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.WindowConfiguration; +import android.compat.annotation.UnsupportedAppUsage; import android.content.LocaleProto; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java index 848790f46734..5e10a5768358 100644 --- a/core/java/android/content/res/ConfigurationBoundResourceCache.java +++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java @@ -16,7 +16,7 @@ package android.content.res; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; /** diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java index 90604b8d536a..5497e61fa2e9 100644 --- a/core/java/android/content/res/DrawableCache.java +++ b/core/java/android/content/res/DrawableCache.java @@ -16,7 +16,7 @@ package android.content.res; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.drawable.Drawable; /** diff --git a/core/java/android/content/res/ObbInfo.java b/core/java/android/content/res/ObbInfo.java index 8af27ca825d0..c477abcea8ba 100644 --- a/core/java/android/content/res/ObbInfo.java +++ b/core/java/android/content/res/ObbInfo.java @@ -16,7 +16,7 @@ package android.content.res; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index d7e4e1452cfe..4f6449ecd4eb 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -39,8 +39,8 @@ import android.annotation.RawRes; import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.StyleableRes; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; import android.graphics.Movie; diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 794be9e202be..86ba0b61fbad 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -27,7 +27,7 @@ import android.annotation.PluralsRes; import android.annotation.RawRes; import android.annotation.StyleRes; import android.annotation.StyleableRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; import android.content.res.AssetManager.AssetInputStream; diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java index 1db2dd85fb37..a29fea09c5ce 100644 --- a/core/java/android/content/res/ResourcesKey.java +++ b/core/java/android/content/res/ResourcesKey.java @@ -18,7 +18,7 @@ package android.content.res; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.text.TextUtils; import java.util.Arrays; diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index b7bc8229fa45..625889216719 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -16,7 +16,7 @@ package android.content.res; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java index 06cafdb2bb91..f24e6f2a89c9 100644 --- a/core/java/android/content/res/ThemedResourceCache.java +++ b/core/java/android/content/res/ThemedResourceCache.java @@ -18,12 +18,12 @@ package android.content.res; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.Resources.Theme; import android.content.res.Resources.ThemeKey; -import android.util.LongSparseArray; import android.util.ArrayMap; +import android.util.LongSparseArray; import java.lang.ref.WeakReference; diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index b79cf6566987..90affdfed39f 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -20,7 +20,7 @@ import android.annotation.AnyRes; import android.annotation.ColorInt; import android.annotation.Nullable; import android.annotation.StyleableRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; import android.graphics.Typeface; diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java index 626bf77046bf..cb93cbfcbfc9 100644 --- a/core/java/android/content/res/XmlBlock.java +++ b/core/java/android/content/res/XmlBlock.java @@ -20,7 +20,7 @@ import static android.content.res.Resources.ID_NULL; import android.annotation.AnyRes; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.TypedValue; import com.android.internal.util.XmlUtils; diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index cc5d3b16ff08..3e10a6c0b849 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -17,7 +17,7 @@ package android.database; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.net.Uri; import android.os.Build; diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java index a988f0684fca..daf7d2b1e908 100644 --- a/core/java/android/database/AbstractWindowedCursor.java +++ b/core/java/android/database/AbstractWindowedCursor.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A base class for Cursors that store their data in {@link CursorWindow}s. diff --git a/core/java/android/database/BulkCursorNative.java b/core/java/android/database/BulkCursorNative.java index 77a13cf80073..8ea450c6ca44 100644 --- a/core/java/android/database/BulkCursorNative.java +++ b/core/java/android/database/BulkCursorNative.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java index 798b7830ac50..69ca581e1559 100644 --- a/core/java/android/database/ContentObserver.java +++ b/core/java/android/database/ContentObserver.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Handler; import android.os.UserHandle; diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java index 6873577553a7..063a2d00a306 100644 --- a/core/java/android/database/CursorWindow.java +++ b/core/java/android/database/CursorWindow.java @@ -17,7 +17,7 @@ package android.database; import android.annotation.BytesLong; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.database.sqlite.SQLiteClosable; import android.database.sqlite.SQLiteException; diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java index c9cafafe4041..4496f805cc2e 100644 --- a/core/java/android/database/CursorWrapper.java +++ b/core/java/android/database/CursorWrapper.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.net.Uri; import android.os.Bundle; diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index 992da312201d..4246b84dc52f 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -17,7 +17,7 @@ package android.database; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentValues; import android.content.Context; import android.content.OperationApplicationException; diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java index b0d399c64ea9..050a49ac959e 100644 --- a/core/java/android/database/MatrixCursor.java +++ b/core/java/android/database/MatrixCursor.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import java.util.ArrayList; diff --git a/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java index 2af06e116da0..ba546f34c9ea 100644 --- a/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java +++ b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An exception that indicates that garbage-collector is finalizing a database object diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java index d6a71da105dd..2fca729f2551 100644 --- a/core/java/android/database/sqlite/SQLiteClosable.java +++ b/core/java/android/database/sqlite/SQLiteClosable.java @@ -16,7 +16,8 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.Closeable; /** diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java index e3c409891c54..4559e918acc5 100644 --- a/core/java/android/database/sqlite/SQLiteCursor.java +++ b/core/java/android/database/sqlite/SQLiteCursor.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.AbstractWindowedCursor; import android.database.CursorWindow; import android.database.DatabaseUtils; diff --git a/core/java/android/database/sqlite/SQLiteCustomFunction.java b/core/java/android/database/sqlite/SQLiteCustomFunction.java index 41b78d3a7745..1ace40d7e913 100644 --- a/core/java/android/database/sqlite/SQLiteCustomFunction.java +++ b/core/java/android/database/sqlite/SQLiteCustomFunction.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; /** diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index caf3e9337b92..7a0e183c03fe 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -20,9 +20,9 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java index fcdaf0abafcb..6a52b72a9e1c 100644 --- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.ArrayList; import java.util.Locale; diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java index 3d0ac611b2df..165f863ccde7 100644 --- a/core/java/android/database/sqlite/SQLiteDebug.java +++ b/core/java/android/database/sqlite/SQLiteDebug.java @@ -17,14 +17,13 @@ package android.database.sqlite; import android.annotation.TestApi; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Process; import android.os.SystemProperties; import android.util.Log; import android.util.Printer; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.ArrayList; /** diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java index 62cec0e1aa92..943afc7e04c3 100644 --- a/core/java/android/database/sqlite/SQLiteOpenHelper.java +++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java @@ -19,7 +19,7 @@ package android.database.sqlite; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.database.DatabaseErrorHandler; import android.database.SQLException; diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java index 8304133cd41e..de1c54321985 100644 --- a/core/java/android/database/sqlite/SQLiteProgram.java +++ b/core/java/android/database/sqlite/SQLiteProgram.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.DatabaseUtils; import android.os.CancellationSignal; diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java index 58901798b5f7..02c8a97a6902 100644 --- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java +++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java @@ -18,7 +18,7 @@ package android.database.sqlite; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentValues; import android.database.Cursor; import android.database.DatabaseUtils; diff --git a/core/java/android/database/sqlite/SQLiteSession.java b/core/java/android/database/sqlite/SQLiteSession.java index a9ac9e7f882f..24b62b89454d 100644 --- a/core/java/android/database/sqlite/SQLiteSession.java +++ b/core/java/android/database/sqlite/SQLiteSession.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.CursorWindow; import android.database.DatabaseUtils; import android.os.CancellationSignal; diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index 42e7ac7e8431..9fda8b011e52 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelFileDescriptor; /** diff --git a/core/java/android/database/sqlite/SqliteWrapper.java b/core/java/android/database/sqlite/SqliteWrapper.java index e3171640a25c..f335fbdd89e0 100644 --- a/core/java/android/database/sqlite/SqliteWrapper.java +++ b/core/java/android/database/sqlite/SqliteWrapper.java @@ -17,12 +17,11 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; -import android.database.sqlite.SQLiteException; import android.net.Uri; import android.util.Log; import android.widget.Toast; diff --git a/core/java/android/ddm/DdmHandleAppName.java b/core/java/android/ddm/DdmHandleAppName.java index 956078772ca8..e6fb4ec25210 100644 --- a/core/java/android/ddm/DdmHandleAppName.java +++ b/core/java/android/ddm/DdmHandleAppName.java @@ -16,11 +16,13 @@ package android.ddm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; +import android.util.Log; + import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; -import android.util.Log; + import java.nio.ByteBuffer; diff --git a/core/java/android/debug/AdbManager.java b/core/java/android/debug/AdbManager.java index ae3d79490c98..0a76bedcd66e 100644 --- a/core/java/android/debug/AdbManager.java +++ b/core/java/android/debug/AdbManager.java @@ -16,15 +16,17 @@ package android.debug; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.os.RemoteException; /** - * This class allows the control of ADB-related functions. Currently only ADB over USB is - * supported, and none of the API is public. - * + * This class allows the control of ADB-related functions. * @hide */ +@SystemApi @SystemService(Context.ADB_SERVICE) public class AdbManager { private static final String TAG = "AdbManager"; @@ -39,4 +41,33 @@ public class AdbManager { mContext = context; mService = service; } + + /** + * @return true if the device supports secure ADB over Wi-Fi. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) + public boolean isAdbWifiSupported() { + try { + return mService.isAdbWifiSupported(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @return true if the device supports secure ADB over Wi-Fi and device pairing by + * QR code. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) + public boolean isAdbWifiQrSupported() { + try { + return mService.isAdbWifiQrSupported(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/debug/IAdbManager.aidl b/core/java/android/debug/IAdbManager.aidl index 79e0794fd9af..c48fc07791c0 100644 --- a/core/java/android/debug/IAdbManager.aidl +++ b/core/java/android/debug/IAdbManager.aidl @@ -41,4 +41,15 @@ interface IAdbManager { * Clear all public keys installed for secure ADB debugging. */ void clearDebuggingKeys(); + + /** + * Returns true if device supports secure Adb over Wi-Fi. + */ + boolean isAdbWifiSupported(); + + /** + * Returns true if device supports secure Adb over Wi-Fi and device pairing by + * QR code. + */ + boolean isAdbWifiQrSupported(); } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 33e51c9fa11c..c847f86f6b62 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -16,14 +16,20 @@ package android.hardware; -import static android.system.OsConstants.*; +import static android.system.OsConstants.EACCES; +import static android.system.OsConstants.EBUSY; +import static android.system.OsConstants.EINVAL; +import static android.system.OsConstants.ENODEV; +import static android.system.OsConstants.ENOSYS; +import static android.system.OsConstants.EOPNOTSUPP; +import static android.system.OsConstants.EUSERS; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.AppOpsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.ImageFormat; import android.graphics.Point; diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java index c569e05112a3..67797510870a 100644 --- a/core/java/android/hardware/HardwareBuffer.java +++ b/core/java/android/hardware/HardwareBuffer.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.LongDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.GraphicBuffer; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index e78fb7f00797..a71a7b63f30e 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -18,7 +18,7 @@ package android.hardware; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; /** diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index 8c910b254b9c..64c45bf290ec 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -16,7 +16,7 @@ package android.hardware; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * This class represents a {@link android.hardware.Sensor Sensor} event and diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index 32504282d98f..6036d7938b95 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -18,7 +18,7 @@ package android.hardware; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java index 571c3cc0451f..b51382e01ccd 100644 --- a/core/java/android/hardware/SerialManager.java +++ b/core/java/android/hardware/SerialManager.java @@ -17,7 +17,7 @@ package android.hardware; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.ParcelFileDescriptor; import android.os.RemoteException; diff --git a/core/java/android/hardware/SerialPort.java b/core/java/android/hardware/SerialPort.java index 78ac3c007793..0fcaa4989210 100644 --- a/core/java/android/hardware/SerialPort.java +++ b/core/java/android/hardware/SerialPort.java @@ -16,12 +16,11 @@ package android.hardware; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelFileDescriptor; import java.io.FileDescriptor; import java.io.IOException; - import java.nio.ByteBuffer; /** diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index 7abfabf4a2ac..974913b290b1 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -16,7 +16,7 @@ package android.hardware; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index 27c04b407315..2333251d0802 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -16,8 +16,8 @@ package android.hardware.biometrics; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java index b025508fc70e..5c74456eb60a 100644 --- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java @@ -16,8 +16,8 @@ package android.hardware.biometrics; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.fingerprint.FingerprintManager; /** diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 1142a07bc66c..2497ea9c7950 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -32,6 +32,7 @@ import android.os.CancellationSignal; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.security.identity.IdentityCredential; import android.text.TextUtils; import android.util.Log; @@ -401,6 +402,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan super(mac); } + public CryptoObject(@NonNull IdentityCredential credential) { + super(credential); + } + /** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. @@ -424,6 +429,14 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan public Mac getMac() { return super.getMac(); } + + /** + * Get {@link IdentityCredential} object. + * @return {@link IdentityCredential} object or null if this doesn't contain one. + */ + public @Nullable IdentityCredential getIdentityCredential() { + return super.getIdentityCredential(); + } } /** diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java index 787dc6696cd3..0af18dfb0e3a 100644 --- a/core/java/android/hardware/biometrics/CryptoObject.java +++ b/core/java/android/hardware/biometrics/CryptoObject.java @@ -17,6 +17,7 @@ package android.hardware.biometrics; import android.annotation.NonNull; +import android.security.identity.IdentityCredential; import android.security.keystore.AndroidKeyStoreProvider; import java.security.Signature; @@ -26,7 +27,8 @@ import javax.crypto.Mac; /** * A wrapper class for the crypto objects supported by BiometricPrompt and FingerprintManager. - * Currently the framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. + * Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac} and + * {@link IdentityCredential} objects. * @hide */ public class CryptoObject { @@ -44,6 +46,10 @@ public class CryptoObject { mCrypto = mac; } + public CryptoObject(@NonNull IdentityCredential credential) { + mCrypto = credential; + } + /** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. @@ -69,11 +75,23 @@ public class CryptoObject { } /** + * Get {@link IdentityCredential} object. + * @return {@link IdentityCredential} object or null if this doesn't contain one. + */ + public IdentityCredential getIdentityCredential() { + return mCrypto instanceof IdentityCredential ? (IdentityCredential) mCrypto : null; + } + + /** * @hide * @return the opId associated with this object or 0 if none */ public final long getOpId() { - return mCrypto != null - ? AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0; + if (mCrypto == null) { + return 0; + } else if (mCrypto instanceof IdentityCredential) { + return ((IdentityCredential) mCrypto).getCredstoreOperationHandle(); + } + return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto); } }; diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 48588e6d40bc..c697d4ce0c4f 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -18,7 +18,7 @@ package android.hardware.camera2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 6a2fc8a2ca34..d027de88a564 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -18,7 +18,7 @@ package android.hardware.camera2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index ba451e585d27..af05b2980bd9 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -18,7 +18,7 @@ package android.hardware.camera2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.CaptureResultExtras; import android.hardware.camera2.impl.PublicKey; diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index e909c0075f38..706aa4ef1979 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -16,12 +16,11 @@ package android.hardware.camera2.impl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.Rect; import android.hardware.camera2.CameraCharacteristics; -import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.marshal.MarshalQueryable; @@ -52,7 +51,6 @@ import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.params.LensShadingMap; import android.hardware.camera2.params.MandatoryStreamCombination; -import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation; import android.hardware.camera2.params.OisSample; import android.hardware.camera2.params.RecommendedStreamConfiguration; import android.hardware.camera2.params.RecommendedStreamConfigurationMap; diff --git a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java index 526f086f4baa..16f3f2ab2023 100644 --- a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java +++ b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java @@ -16,7 +16,7 @@ package android.hardware.camera2.utils; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Provide hashing functions using the Modified Bernstein hash diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java index d3c4505c37f0..abe1372ebde4 100644 --- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java +++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java @@ -16,7 +16,7 @@ package android.hardware.camera2.utils; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.ImageFormat; import android.hardware.camera2.legacy.LegacyCameraDevice; import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException; diff --git a/core/java/android/hardware/camera2/utils/TypeReference.java b/core/java/android/hardware/camera2/utils/TypeReference.java index d9ba31b4c6f4..435ed153e042 100644 --- a/core/java/android/hardware/camera2/utils/TypeReference.java +++ b/core/java/android/hardware/camera2/utils/TypeReference.java @@ -16,7 +16,10 @@ package android.hardware.camera2.utils; -import android.annotation.UnsupportedAppUsage; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.compat.annotation.UnsupportedAppUsage; + import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; @@ -24,8 +27,6 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; -import static com.android.internal.util.Preconditions.*; - /** * Super type token; allows capturing generic types at runtime by forcing them to be reified. * diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 0b25dbd78611..799dff9632c8 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -23,8 +23,8 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Point; import android.media.projection.MediaProjection; diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index ea63776dc5b6..2a584951887f 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -18,7 +18,7 @@ package android.hardware.display; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ParceledListSlice; import android.content.res.Resources; diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java index 55e60519707a..5bbbbf9bae77 100644 --- a/core/java/android/hardware/display/WifiDisplay.java +++ b/core/java/android/hardware/display/WifiDisplay.java @@ -16,7 +16,7 @@ package android.hardware.display; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java index 1973e51b1bba..e2a825fd990a 100644 --- a/core/java/android/hardware/display/WifiDisplayStatus.java +++ b/core/java/android/hardware/display/WifiDisplayStatus.java @@ -16,7 +16,7 @@ package android.hardware.display; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index d0622c88b4ca..16f96888bb0a 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -26,8 +26,8 @@ import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; @@ -44,6 +44,7 @@ import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; +import android.security.identity.IdentityCredential; import android.util.Slog; import java.security.Signature; @@ -125,6 +126,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing super(mac); } + public CryptoObject(@NonNull IdentityCredential credential) { + super(credential); + } + /** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. @@ -148,6 +153,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing public Mac getMac() { return super.getMac(); } + + /** + * Get {@link IdentityCredential} object. + * @return {@link IdentityCredential} object or null if this doesn't contain one. + */ + public @Nullable IdentityCredential getIdentityCredential() { + return super.getIdentityCredential(); + } } /** diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 0c0f248e3222..8d32db013fb3 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.AudioAttributes; import android.os.Binder; diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java index 23d8d01dbe9d..a1866af43706 100644 --- a/core/java/android/hardware/location/GeofenceHardware.java +++ b/core/java/android/hardware/location/GeofenceHardware.java @@ -16,7 +16,7 @@ package android.hardware.location; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.location.Location; import android.os.Build; import android.os.RemoteException; diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index f96f47dfaffc..2f0265acf4bd 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -25,8 +25,8 @@ import static android.system.OsConstants.EPIPE; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioFormat; import android.os.Handler; import android.os.Parcel; diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java index 911354862ff4..694d60531396 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -16,7 +16,7 @@ package android.hardware.soundtrigger; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; import android.os.Message; diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index 08c9eea6e012..fdb4cc079bd7 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -18,8 +18,8 @@ package android.hardware.usb; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index 71297c187e5c..215ac24fcb08 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.ParcelFileDescriptor; diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index eb148b94ac7b..67fdda37ed3b 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -26,8 +26,8 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -91,7 +91,7 @@ public class UsbManager { * * {@hide} */ - @UnsupportedAppUsage + @SystemApi public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE"; @@ -164,7 +164,7 @@ public class UsbManager { * * {@hide} */ - @UnsupportedAppUsage + @SystemApi public static final String USB_CONNECTED = "connected"; /** @@ -181,6 +181,7 @@ public class UsbManager { * * {@hide} */ + @SystemApi public static final String USB_CONFIGURED = "configured"; /** @@ -217,6 +218,7 @@ public class UsbManager { * * {@hide} */ + @SystemApi public static final String USB_FUNCTION_RNDIS = "rndis"; /** @@ -319,6 +321,7 @@ public class UsbManager { * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)} * {@hide} */ + @SystemApi public static final long FUNCTION_NONE = 0; /** @@ -337,6 +340,7 @@ public class UsbManager { * Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)} * {@hide} */ + @SystemApi public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS; /** @@ -698,6 +702,8 @@ public class UsbManager { * * {@hide} */ + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long functions) { try { mService.setCurrentFunctions(functions); @@ -737,6 +743,8 @@ public class UsbManager { * * {@hide} */ + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_USB) public long getCurrentFunctions() { try { return mService.getCurrentFunctions(); diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java index 7abf3e9bcc7a..fab2c0baa10e 100644 --- a/core/java/android/hardware/usb/UsbRequest.java +++ b/core/java/android/hardware/usb/UsbRequest.java @@ -17,7 +17,7 @@ package android.hardware.usb; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.util.Log; diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 7d4849f7562d..9327b241c6c5 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -16,7 +16,7 @@ package android.inputmethodservice; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.os.Bundle; diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index a47f601033cf..69b93b19fc41 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -18,7 +18,7 @@ package android.inputmethodservice; import android.annotation.BinderThread; import android.annotation.MainThread; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 82d4d1d10d7e..44825a8f1502 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -30,9 +30,9 @@ import android.annotation.IntDef; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.Dialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java index 3f25113874e8..c85fcd990564 100644 --- a/core/java/android/inputmethodservice/Keyboard.java +++ b/core/java/android/inputmethodservice/Keyboard.java @@ -16,8 +16,8 @@ package android.inputmethodservice; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index 45f067b95298..b780b21bf3d0 100644 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -16,7 +16,7 @@ package android.inputmethodservice; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index a66fcae7d4a2..fb35b4bde303 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -60,6 +60,18 @@ public class CaptivePortal implements Parcelable { @SystemApi @TestApi public static final int APP_RETURN_WANTED_AS_IS = 2; + /** Event offset of request codes from captive portal application. */ + private static final int APP_REQUEST_BASE = 100; + /** + * Request code from the captive portal application, indicating that the network condition may + * have changed and the network should be re-validated. + * @see ICaptivePortal#appRequest(int) + * @see android.net.INetworkMonitor#forceReevaluation(int) + * @hide + */ + @SystemApi + @TestApi + public static final int APP_REQUEST_REEVALUATION_REQUIRED = APP_REQUEST_BASE + 0; private final IBinder mBinder; @@ -136,6 +148,19 @@ public class CaptivePortal implements Parcelable { } /** + * Request that the system reevaluates the captive portal status. + * @hide + */ + @SystemApi + @TestApi + public void reevaluateNetwork() { + try { + ICaptivePortal.Stub.asInterface(mBinder).appRequest(APP_REQUEST_REEVALUATION_REQUIRED); + } catch (RemoteException e) { + } + } + + /** * Log a captive portal login event. * @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto. * @param packageName captive portal application package name. diff --git a/core/java/android/net/CaptivePortalData.aidl b/core/java/android/net/CaptivePortalData.aidl new file mode 100644 index 000000000000..1d57ee759136 --- /dev/null +++ b/core/java/android/net/CaptivePortalData.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +@JavaOnlyStableParcelable parcelable CaptivePortalData; diff --git a/core/java/android/net/CaptivePortalData.java b/core/java/android/net/CaptivePortalData.java new file mode 100644 index 000000000000..1357803a6cb8 --- /dev/null +++ b/core/java/android/net/CaptivePortalData.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Metadata sent by captive portals, see https://www.ietf.org/id/draft-ietf-capport-api-03.txt. + * @hide + */ +@SystemApi +@TestApi +public final class CaptivePortalData implements Parcelable { + private final long mRefreshTimeMillis; + @Nullable + private final Uri mUserPortalUrl; + @Nullable + private final Uri mVenueInfoUrl; + private final boolean mIsSessionExtendable; + private final long mByteLimit; + private final long mExpiryTimeMillis; + private final boolean mCaptive; + + private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl, + boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive) { + mRefreshTimeMillis = refreshTimeMillis; + mUserPortalUrl = userPortalUrl; + mVenueInfoUrl = venueInfoUrl; + mIsSessionExtendable = isSessionExtendable; + mByteLimit = byteLimit; + mExpiryTimeMillis = expiryTimeMillis; + mCaptive = captive; + } + + private CaptivePortalData(Parcel p) { + this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(), + p.readLong(), p.readLong(), p.readBoolean()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mRefreshTimeMillis); + dest.writeParcelable(mUserPortalUrl, 0); + dest.writeParcelable(mVenueInfoUrl, 0); + dest.writeBoolean(mIsSessionExtendable); + dest.writeLong(mByteLimit); + dest.writeLong(mExpiryTimeMillis); + dest.writeBoolean(mCaptive); + } + + /** + * A builder to create new {@link CaptivePortalData}. + */ + public static class Builder { + private long mRefreshTime; + private Uri mUserPortalUrl; + private Uri mVenueInfoUrl; + private boolean mIsSessionExtendable; + private long mBytesRemaining = -1; + private long mExpiryTime = -1; + private boolean mCaptive; + + /** + * Create an empty builder. + */ + public Builder() {} + + /** + * Create a builder copying all data from existing {@link CaptivePortalData}. + */ + public Builder(@Nullable CaptivePortalData data) { + if (data == null) return; + setRefreshTime(data.mRefreshTimeMillis) + .setUserPortalUrl(data.mUserPortalUrl) + .setVenueInfoUrl(data.mVenueInfoUrl) + .setSessionExtendable(data.mIsSessionExtendable) + .setBytesRemaining(data.mByteLimit) + .setExpiryTime(data.mExpiryTimeMillis) + .setCaptive(data.mCaptive); + } + + /** + * Set the time at which data was last refreshed, as per {@link System#currentTimeMillis()}. + */ + @NonNull + public Builder setRefreshTime(long refreshTime) { + mRefreshTime = refreshTime; + return this; + } + + /** + * Set the URL to be used for users to login to the portal, if captive. + */ + @NonNull + public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) { + mUserPortalUrl = userPortalUrl; + return this; + } + + /** + * Set the URL that can be used by users to view information about the network venue. + */ + @NonNull + public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) { + mVenueInfoUrl = venueInfoUrl; + return this; + } + + /** + * Set whether the portal supports extending a user session on the portal URL page. + */ + @NonNull + public Builder setSessionExtendable(boolean sessionExtendable) { + mIsSessionExtendable = sessionExtendable; + return this; + } + + /** + * Set the number of bytes remaining on the network before the portal closes. + */ + @NonNull + public Builder setBytesRemaining(long bytesRemaining) { + mBytesRemaining = bytesRemaining; + return this; + } + + /** + * Set the time at the session will expire, as per {@link System#currentTimeMillis()}. + */ + @NonNull + public Builder setExpiryTime(long expiryTime) { + mExpiryTime = expiryTime; + return this; + } + + /** + * Set whether the network is captive (portal closed). + */ + @NonNull + public Builder setCaptive(boolean captive) { + mCaptive = captive; + return this; + } + + /** + * Create a new {@link CaptivePortalData}. + */ + @NonNull + public CaptivePortalData build() { + return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl, + mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive); + } + } + + /** + * Get the time at which data was last refreshed, as per {@link System#currentTimeMillis()}. + */ + public long getRefreshTimeMillis() { + return mRefreshTimeMillis; + } + + /** + * Get the URL to be used for users to login to the portal, or extend their session if + * {@link #isSessionExtendable()} is true. + */ + @Nullable + public Uri getUserPortalUrl() { + return mUserPortalUrl; + } + + /** + * Get the URL that can be used by users to view information about the network venue. + */ + @Nullable + public Uri getVenueInfoUrl() { + return mVenueInfoUrl; + } + + /** + * Indicates whether the user portal URL can be used to extend sessions, when the user is logged + * in and the session has a time or byte limit. + */ + public boolean isSessionExtendable() { + return mIsSessionExtendable; + } + + /** + * Get the remaining bytes on the captive portal session, at the time {@link CaptivePortalData} + * was refreshed. This may be different from the limit currently enforced by the portal. + * @return The byte limit, or -1 if not set. + */ + public long getByteLimit() { + return mByteLimit; + } + + /** + * Get the time at the session will expire, as per {@link System#currentTimeMillis()}. + * @return The expiry time, or -1 if unset. + */ + public long getExpiryTimeMillis() { + return mExpiryTimeMillis; + } + + /** + * Get whether the network is captive (portal closed). + */ + public boolean isCaptive() { + return mCaptive; + } + + @NonNull + public static final Creator<CaptivePortalData> CREATOR = new Creator<CaptivePortalData>() { + @Override + public CaptivePortalData createFromParcel(Parcel source) { + return new CaptivePortalData(source); + } + + @Override + public CaptivePortalData[] newArray(int size) { + return new CaptivePortalData[size]; + } + }; + + @Override + public int hashCode() { + return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl, + mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof CaptivePortalData)) return false; + final CaptivePortalData other = (CaptivePortalData) obj; + return mRefreshTimeMillis == other.mRefreshTimeMillis + && Objects.equals(mUserPortalUrl, other.mUserPortalUrl) + && Objects.equals(mVenueInfoUrl, other.mVenueInfoUrl) + && mIsSessionExtendable == other.mIsSessionExtendable + && mByteLimit == other.mByteLimit + && mExpiryTimeMillis == other.mExpiryTimeMillis + && mCaptive == other.mCaptive; + } + + @Override + public String toString() { + return "CaptivePortalData {" + + "refreshTime: " + mRefreshTimeMillis + + ", userPortalUrl: " + mUserPortalUrl + + ", venueInfoUrl: " + mVenueInfoUrl + + ", isSessionExtendable: " + mIsSessionExtendable + + ", byteLimit: " + mByteLimit + + ", expiryTime: " + mExpiryTimeMillis + + ", captive: " + mCaptive + + "}"; + } +} diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java new file mode 100644 index 000000000000..6afdb5ef1b16 --- /dev/null +++ b/core/java/android/net/ConnectivityDiagnosticsManager.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.PersistableBundle; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; + +/** + * Class that provides utilities for collecting network connectivity diagnostics information. + * Connectivity information is made available through triggerable diagnostics tools and by listening + * to System validations. Some diagnostics information may be permissions-restricted. + * + * <p>ConnectivityDiagnosticsManager is intended for use by applications offering network + * connectivity on a user device. These tools will provide several mechanisms for these applications + * to be alerted to network conditions as well as diagnose potential network issues themselves. + * + * <p>The primary responsibilities of this class are to: + * + * <ul> + * <li>Allow permissioned applications to register and unregister callbacks for network event + * notifications + * <li>Invoke callbacks for network event notifications, including: + * <ul> + * <li>Network validations + * <li>Data stalls + * <li>Connectivity reports from applications + * </ul> + * </ul> + */ +public class ConnectivityDiagnosticsManager { + public static final int DETECTION_METHOD_DNS_EVENTS = 1; + public static final int DETECTION_METHOD_TCP_METRICS = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"DETECTION_METHOD_"}, + value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS}) + public @interface DetectionMethod {} + + /** @hide */ + public ConnectivityDiagnosticsManager() {} + + /** Class that includes connectivity information for a specific Network at a specific time. */ + public static class ConnectivityReport { + /** The Network for which this ConnectivityReport applied */ + @NonNull public final Network network; + + /** + * The timestamp for the report. The timestamp is taken from {@link + * System#currentTimeMillis}. + */ + public final long reportTimestamp; + + /** LinkProperties available on the Network at the reported timestamp */ + @NonNull public final LinkProperties linkProperties; + + /** NetworkCapabilities available on the Network at the reported timestamp */ + @NonNull public final NetworkCapabilities networkCapabilities; + + /** PersistableBundle that may contain additional info about the report */ + @NonNull public final PersistableBundle additionalInfo; + + /** + * Constructor for ConnectivityReport. + * + * <p>Apps should obtain instances through {@link + * ConnectivityDiagnosticsCallback#onConnectivityReport} instead of instantiating their own + * instances (unless for testing purposes). + * + * @param network The Network for which this ConnectivityReport applies + * @param reportTimestamp The timestamp for the report + * @param linkProperties The LinkProperties available on network at reportTimestamp + * @param networkCapabilities The NetworkCapabilities available on network at + * reportTimestamp + * @param additionalInfo A PersistableBundle that may contain additional info about the + * report + */ + public ConnectivityReport( + @NonNull Network network, + long reportTimestamp, + @NonNull LinkProperties linkProperties, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull PersistableBundle additionalInfo) { + this.network = network; + this.reportTimestamp = reportTimestamp; + this.linkProperties = linkProperties; + this.networkCapabilities = networkCapabilities; + this.additionalInfo = additionalInfo; + } + } + + /** Class that includes information for a suspected data stall on a specific Network */ + public static class DataStallReport { + /** The Network for which this DataStallReport applied */ + @NonNull public final Network network; + + /** + * The timestamp for the report. The timestamp is taken from {@link + * System#currentTimeMillis}. + */ + public final long reportTimestamp; + + /** The detection method used to identify the suspected data stall */ + @DetectionMethod public final int detectionMethod; + + /** PersistableBundle that may contain additional information on the suspected data stall */ + @NonNull public final PersistableBundle stallDetails; + + /** + * Constructor for DataStallReport. + * + * <p>Apps should obtain instances through {@link + * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own + * instances (unless for testing purposes). + * + * @param network The Network for which this DataStallReport applies + * @param reportTimestamp The timestamp for the report + * @param detectionMethod The detection method used to identify this data stall + * @param stallDetails A PersistableBundle that may contain additional info about the report + */ + public DataStallReport( + @NonNull Network network, + long reportTimestamp, + @DetectionMethod int detectionMethod, + @NonNull PersistableBundle stallDetails) { + this.network = network; + this.reportTimestamp = reportTimestamp; + this.detectionMethod = detectionMethod; + this.stallDetails = stallDetails; + } + } + + /** + * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about + * network connectivity events. Must be extended by applications wanting notifications. + */ + public abstract static class ConnectivityDiagnosticsCallback { + /** + * Called when the platform completes a data connectivity check. This will also be invoked + * upon registration with the latest report. + * + * <p>The Network specified in the ConnectivityReport may not be active any more when this + * method is invoked. + * + * @param report The ConnectivityReport containing information about a connectivity check + */ + public void onConnectivityReport(@NonNull ConnectivityReport report) {} + + /** + * Called when the platform suspects a data stall on some Network. + * + * <p>The Network specified in the DataStallReport may not be active any more when this + * method is invoked. + * + * @param report The DataStallReport containing information about the suspected data stall + */ + public void onDataStallSuspected(@NonNull DataStallReport report) {} + + /** + * Called when any app reports connectivity to the System. + * + * @param network The Network for which connectivity has been reported + * @param hasConnectivity The connectivity reported to the System + */ + public void onNetworkConnectivityReported( + @NonNull Network network, boolean hasConnectivity) {} + } + + /** + * Registers a ConnectivityDiagnosticsCallback with the System. + * + * <p>Only apps that offer network connectivity to the user are allowed to register callbacks. + * This includes: + * + * <ul> + * <li>Carrier apps with active subscriptions + * <li>Active VPNs + * <li>WiFi Suggesters + * </ul> + * + * <p>Callbacks will be limited to receiving notifications for networks over which apps provide + * connectivity. + * + * <p>If a registering app loses its relevant permissions, any callbacks it registered will + * silently stop receiving callbacks. + * + * <p>Each register() call <b>MUST</b> use a unique ConnectivityDiagnosticsCallback instance. If + * a single instance is registered with multiple NetworkRequests, an IllegalArgumentException + * will be thrown. + * + * @param request The NetworkRequest that will be used to match with Networks for which + * callbacks will be fired + * @param e The Executor to be used for running the callback method invocations + * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the + * System + * @throws IllegalArgumentException if the same callback instance is registered with multiple + * NetworkRequests + * @throws SecurityException if the caller does not have appropriate permissions to register a + * callback + */ + public void registerConnectivityDiagnosticsCallback( + @NonNull NetworkRequest request, + @NonNull Executor e, + @NonNull ConnectivityDiagnosticsCallback callback) { + // TODO(b/143187964): implement ConnectivityDiagnostics functionality + throw new UnsupportedOperationException("registerCallback() not supported yet"); + } + + /** + * Unregisters a ConnectivityDiagnosticsCallback with the System. + * + * <p>If the given callback is not currently registered with the System, this operation will be + * a no-op. + * + * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System. + */ + public void unregisterConnectivityDiagnosticsCallback( + @NonNull ConnectivityDiagnosticsCallback callback) { + // TODO(b/143187964): implement ConnectivityDiagnostics functionality + throw new UnsupportedOperationException("registerCallback() not supported yet"); + } +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 82cecb6f20ad..11c1a9c32d8a 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -27,8 +27,8 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.net.IpSecManager.UdpEncapsulationSocket; @@ -363,7 +363,7 @@ public class ConnectivityManager { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @UnsupportedAppUsage public static final String ACTION_TETHER_STATE_CHANGED = - "android.net.conn.TETHER_STATE_CHANGED"; + TetheringManager.ACTION_TETHER_STATE_CHANGED; /** * @hide @@ -371,14 +371,14 @@ public class ConnectivityManager { * tethering and currently available for tethering. */ @UnsupportedAppUsage - public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; + public static final String EXTRA_AVAILABLE_TETHER = TetheringManager.EXTRA_AVAILABLE_TETHER; /** * @hide * gives a String[] listing all the interfaces currently in local-only * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding) */ - public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray"; + public static final String EXTRA_ACTIVE_LOCAL_ONLY = TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; /** * @hide @@ -386,7 +386,7 @@ public class ConnectivityManager { * (ie, has DHCPv4 support and packets potentially forwarded/NATed) */ @UnsupportedAppUsage - public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; + public static final String EXTRA_ACTIVE_TETHER = TetheringManager.EXTRA_ACTIVE_TETHER; /** * @hide @@ -395,7 +395,7 @@ public class ConnectivityManager { * for any interfaces listed here. */ @UnsupportedAppUsage - public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + public static final String EXTRA_ERRORED_TETHER = TetheringManager.EXTRA_ERRORED_TETHER; /** * Broadcast Action: The captive portal tracker has finished its test. @@ -445,7 +445,7 @@ public class ConnectivityManager { * @see #startTethering(int, boolean, OnStartTetheringCallback) * @hide */ - public static final int TETHERING_INVALID = -1; + public static final int TETHERING_INVALID = TetheringManager.TETHERING_INVALID; /** * Wifi tethering type. @@ -453,7 +453,7 @@ public class ConnectivityManager { * @hide */ @SystemApi - public static final int TETHERING_WIFI = 0; + public static final int TETHERING_WIFI = TetheringManager.TETHERING_WIFI; /** * USB tethering type. @@ -461,7 +461,7 @@ public class ConnectivityManager { * @hide */ @SystemApi - public static final int TETHERING_USB = 1; + public static final int TETHERING_USB = TetheringManager.TETHERING_USB; /** * Bluetooth tethering type. @@ -469,7 +469,7 @@ public class ConnectivityManager { * @hide */ @SystemApi - public static final int TETHERING_BLUETOOTH = 2; + public static final int TETHERING_BLUETOOTH = TetheringManager.TETHERING_BLUETOOTH; /** * Wifi P2p tethering type. @@ -477,47 +477,47 @@ public class ConnectivityManager { * need to start from #startTethering(int, boolean, OnStartTetheringCallback). * @hide */ - public static final int TETHERING_WIFI_P2P = 3; + public static final int TETHERING_WIFI_P2P = TetheringManager.TETHERING_WIFI_P2P; /** * Extra used for communicating with the TetherService. Includes the type of tethering to * enable if any. * @hide */ - public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; + public static final String EXTRA_ADD_TETHER_TYPE = TetheringManager.EXTRA_ADD_TETHER_TYPE; /** * Extra used for communicating with the TetherService. Includes the type of tethering for * which to cancel provisioning. * @hide */ - public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType"; + public static final String EXTRA_REM_TETHER_TYPE = TetheringManager.EXTRA_REM_TETHER_TYPE; /** * Extra used for communicating with the TetherService. True to schedule a recheck of tether * provisioning. * @hide */ - public static final String EXTRA_SET_ALARM = "extraSetAlarm"; + public static final String EXTRA_SET_ALARM = TetheringManager.EXTRA_SET_ALARM; /** * Tells the TetherService to run a provision check now. * @hide */ - public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; + public static final String EXTRA_RUN_PROVISION = TetheringManager.EXTRA_RUN_PROVISION; /** * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver} * which will receive provisioning results. Can be left empty. * @hide */ - public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback"; + public static final String EXTRA_PROVISION_CALLBACK = TetheringManager.EXTRA_PROVISION_CALLBACK; /** * The absence of a connection type. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + @SystemApi public static final int TYPE_NONE = -1; /** @@ -662,7 +662,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @SystemApi public static final int TYPE_WIFI_P2P = 13; /** @@ -3107,6 +3107,61 @@ public class ConnectivityManager { } } + /** + * Registers the specified {@link NetworkProvider}. + * Each listener must only be registered once. The listener can be unregistered with + * {@link #unregisterNetworkProvider}. + * + * @param provider the provider to register + * @return the ID of the provider. This ID must be used by the provider when registering + * {@link android.net.NetworkAgent}s. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public int registerNetworkProvider(@NonNull NetworkProvider provider) { + if (provider.getProviderId() != NetworkProvider.ID_NONE) { + throw new IllegalStateException("NetworkProviders can only be registered once"); + } + + try { + int providerId = mService.registerNetworkProvider(provider.getMessenger(), + provider.getName()); + provider.setProviderId(providerId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return provider.getProviderId(); + } + + /** + * Unregisters the specified NetworkProvider. + * + * @param provider the provider to unregister + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void unregisterNetworkProvider(@NonNull NetworkProvider provider) { + try { + mService.unregisterNetworkProvider(provider.getMessenger()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + provider.setProviderId(NetworkProvider.ID_NONE); + } + + + /** @hide exposed via the NetworkProvider class. */ + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { + try { + mService.declareNetworkRequestUnfulfillable(request); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + // TODO : remove this method. It is a stopgap measure to help sheperding a number // of dependent changes that would conflict throughout the automerger graph. Having this // temporarily helps with the process of going through with all these dependent changes across @@ -3114,26 +3169,25 @@ public class ConnectivityManager { /** * @hide * Register a NetworkAgent with ConnectivityService. - * @return NetID corresponding to NetworkAgent. + * @return Network corresponding to NetworkAgent. */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, - NetworkCapabilities nc, int score, NetworkMisc misc) { - return registerNetworkAgent(messenger, ni, lp, nc, score, misc, - NetworkFactory.SerialNumber.NONE); + public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + NetworkCapabilities nc, int score, NetworkAgentConfig config) { + return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE); } /** * @hide * Register a NetworkAgent with ConnectivityService. - * @return NetID corresponding to NetworkAgent. + * @return Network corresponding to NetworkAgent. */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, - NetworkCapabilities nc, int score, NetworkMisc misc, int factorySerialNumber) { + public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) { + try { - return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc, - factorySerialNumber); + return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3569,14 +3623,26 @@ public class ConnectivityManager { /** * Helper function to request a network with a particular legacy type. * - * This is temporarily public @hide so it can be called by system code that uses the - * NetworkRequest API to request networks but relies on CONNECTIVITY_ACTION broadcasts for - * instead network notifications. + * @deprecated This is temporarily public for tethering to backwards compatibility that uses + * the NetworkRequest API to request networks with legacy type and relies on + * CONNECTIVITY_ACTION broadcasts instead of NetworkCallbacks. New caller should use + * {@link #requestNetwork(NetworkRequest, NetworkCallback, Handler)} instead. * * TODO: update said system code to rely on NetworkCallbacks and make this method private. + + * @param request {@link NetworkRequest} describing this request. + * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note + * the callback must not be shared - it uniquely specifies this request. + * @param timeoutMs The time in milliseconds to attempt looking for a suitable network + * before {@link NetworkCallback#onUnavailable()} is called. The timeout must + * be a positive value (i.e. >0). + * @param legacyType to specify the network type(#TYPE_*). + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. * * @hide */ + @SystemApi + @Deprecated public void requestNetwork(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback, int timeoutMs, int legacyType, @NonNull Handler handler) { diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index 98bab44e19fb..912df67a0b45 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -16,8 +16,8 @@ package android.net; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; /** * A simple object for retrieving the results of a DHCP request. @@ -67,12 +67,12 @@ public class DhcpInfo implements Parcelable { buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress()); } - /** Implement the Parcelable interface {@hide} */ + /** Implement the Parcelable interface */ public int describeContents() { return 0; } - /** Implement the Parcelable interface {@hide} */ + /** Implement the Parcelable interface */ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(ipAddress); dest.writeInt(gateway); @@ -83,7 +83,7 @@ public class DhcpInfo implements Parcelable { dest.writeInt(leaseDuration); } - /** Implement the Parcelable interface {@hide} */ + /** Implement the Parcelable interface */ public static final @android.annotation.NonNull Creator<DhcpInfo> CREATOR = new Creator<DhcpInfo>() { public DhcpInfo createFromParcel(Parcel in) { diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java index 97be51a30641..059cd94accfe 100644 --- a/core/java/android/net/DhcpResults.java +++ b/core/java/android/net/DhcpResults.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.shared.InetAddressUtils; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 72565024d3a5..fd015b4fe52c 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,7 +17,7 @@ package android.net; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; import android.os.Message; diff --git a/core/java/android/net/ICaptivePortal.aidl b/core/java/android/net/ICaptivePortal.aidl index 707b4f699873..fe21905c7002 100644 --- a/core/java/android/net/ICaptivePortal.aidl +++ b/core/java/android/net/ICaptivePortal.aidl @@ -21,6 +21,7 @@ package android.net; * @hide */ oneway interface ICaptivePortal { + void appRequest(int request); void appResponse(int response); void logEvent(int eventId, String packageName); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 09c02efbcfc4..186196bd31c7 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -20,9 +20,9 @@ import android.app.PendingIntent; import android.net.ConnectionInfo; import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; -import android.net.NetworkMisc; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkState; @@ -142,14 +142,19 @@ interface IConnectivityManager void setAirplaneMode(boolean enable); - int registerNetworkFactory(in Messenger messenger, in String name); - boolean requestBandwidthUpdate(in Network network); + int registerNetworkFactory(in Messenger messenger, in String name); void unregisterNetworkFactory(in Messenger messenger); - int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, - in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber); + int registerNetworkProvider(in Messenger messenger, in String name); + void unregisterNetworkProvider(in Messenger messenger); + + void declareNetworkRequestUnfulfillable(in NetworkRequest request); + + Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, + in NetworkCapabilities nc, int score, in NetworkAgentConfig config, + in int factorySerialNumber); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, in Messenger messenger, int timeoutSec, in IBinder binder, int legacy); diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl index 10667aecd128..fe9141cb6a20 100644 --- a/core/java/android/net/INetworkPolicyListener.aidl +++ b/core/java/android/net/INetworkPolicyListener.aidl @@ -15,6 +15,7 @@ */ package android.net; +import android.telephony.SubscriptionPlan; /** {@hide} */ oneway interface INetworkPolicyListener { @@ -23,4 +24,5 @@ oneway interface INetworkPolicyListener { void onRestrictBackgroundChanged(boolean restrictBackground); void onUidPoliciesChanged(int uid, int uidPolicies); void onSubscriptionOverride(int subId, int overrideMask, int overrideValue); + void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans); } diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 385cb1d68b57..72a6b397a30c 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -57,9 +57,6 @@ interface INetworkPolicyManager { @UnsupportedAppUsage boolean getRestrictBackground(); - /** Callback used to change internal state on tethering */ - void onTetheringChanged(String iface, boolean tethering); - /** Gets the restrict background status based on the caller's UID: 1 - disabled 2 - whitelisted diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 9994f9f82b07..5fa515a14343 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -23,6 +23,8 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.net.netstats.provider.INetworkStatsProvider; +import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.IBinder; import android.os.Messenger; import com.android.internal.net.VpnInfo; @@ -89,4 +91,7 @@ interface INetworkStatsService { /** Get the total network stats information since boot */ long getTotalStats(int type); + /** Registers a network stats provider */ + INetworkStatsProviderCallback registerNetworkStatsProvider(String tag, + in INetworkStatsProvider provider); } diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java index 1ae44e169851..37425ffc18aa 100644 --- a/core/java/android/net/InterfaceConfiguration.java +++ b/core/java/android/net/InterfaceConfiguration.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/InvalidPacketException.java b/core/java/android/net/InvalidPacketException.java new file mode 100644 index 000000000000..909998d4562c --- /dev/null +++ b/core/java/android/net/InvalidPacketException.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntDef; +import android.annotation.SystemApi; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Thrown when a packet is invalid. + * @hide + */ +@SystemApi +public class InvalidPacketException extends Exception { + public final int error; + + // Must match SocketKeepalive#ERROR_INVALID_IP_ADDRESS. + /** Invalid IP address. */ + public static final int ERROR_INVALID_IP_ADDRESS = -21; + + // Must match SocketKeepalive#ERROR_INVALID_PORT. + /** Invalid port number. */ + public static final int ERROR_INVALID_PORT = -22; + + // Must match SocketKeepalive#ERROR_INVALID_LENGTH. + /** Invalid packet length. */ + public static final int ERROR_INVALID_LENGTH = -23; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "ERROR_" }, value = { + ERROR_INVALID_IP_ADDRESS, + ERROR_INVALID_PORT, + ERROR_INVALID_LENGTH + }) + public @interface ErrorCode {} + + /** + * This packet is invalid. + * See the error code for details. + */ + public InvalidPacketException(@ErrorCode final int error) { + this.error = error; + } +} diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index dddb64d8cece..23d5ff7f3afe 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -20,8 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; -import android.net.StaticIpConfiguration; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 45d0c7313fca..09ec6c35fcb9 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -17,7 +17,6 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; @@ -26,6 +25,7 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; import android.content.pm.PackageManager; +import android.net.annotations.PolicyDirection; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -41,8 +41,6 @@ import dalvik.system.CloseGuard; import java.io.FileDescriptor; import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; @@ -78,11 +76,6 @@ public final class IpSecManager { */ public static final int DIRECTION_OUT = 1; - /** @hide */ - @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) - @Retention(RetentionPolicy.SOURCE) - public @interface PolicyDirection {} - /** * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. * diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java index 9b8b7322cd23..2b8b7e69dec9 100644 --- a/core/java/android/net/KeepalivePacketData.java +++ b/core/java/android/net/KeepalivePacketData.java @@ -16,13 +16,13 @@ package android.net; -import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; -import static android.net.SocketKeepalive.ERROR_INVALID_PORT; +import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS; +import static android.net.InvalidPacketException.ERROR_INVALID_PORT; -import android.net.SocketKeepalive.InvalidPacketException; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.net.util.IpUtils; import android.os.Parcel; -import android.os.Parcelable; import android.util.Log; import java.net.InetAddress; @@ -33,13 +33,16 @@ import java.net.InetAddress; * * @hide */ -public class KeepalivePacketData implements Parcelable { +@SystemApi +public class KeepalivePacketData { private static final String TAG = "KeepalivePacketData"; /** Source IP address */ + @NonNull public final InetAddress srcAddress; /** Destination IP address */ + @NonNull public final InetAddress dstAddress; /** Source port */ @@ -51,13 +54,14 @@ public class KeepalivePacketData implements Parcelable { /** Packet data. A raw byte string of packet data, not including the link-layer header. */ private final byte[] mPacket; - protected static final int IPV4_HEADER_LENGTH = 20; - protected static final int UDP_HEADER_LENGTH = 8; - // This should only be constructed via static factory methods, such as - // nattKeepalivePacket - protected KeepalivePacketData(InetAddress srcAddress, int srcPort, - InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException { + // nattKeepalivePacket. + /** + * A holding class for data necessary to build a keepalive packet. + */ + protected KeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort, + @NonNull InetAddress dstAddress, int dstPort, + @NonNull byte[] data) throws InvalidPacketException { this.srcAddress = srcAddress; this.dstAddress = dstAddress; this.srcPort = srcPort; @@ -78,16 +82,12 @@ public class KeepalivePacketData implements Parcelable { } } + @NonNull public byte[] getPacket() { return mPacket.clone(); } - /* Parcelable Implementation */ - public int describeContents() { - return 0; - } - - /** Write to parcel */ + /** @hide */ public void writeToParcel(Parcel out, int flags) { out.writeString(srcAddress.getHostAddress()); out.writeString(dstAddress.getHostAddress()); @@ -96,6 +96,7 @@ public class KeepalivePacketData implements Parcelable { out.writeByteArray(mPacket); } + /** @hide */ protected KeepalivePacketData(Parcel in) { srcAddress = NetworkUtils.numericToInetAddress(in.readString()); dstAddress = NetworkUtils.numericToInetAddress(in.readString()); @@ -103,17 +104,4 @@ public class KeepalivePacketData implements Parcelable { dstPort = in.readInt(); mPacket = in.createByteArray(); } - - /** Parcelable Creator */ - public static final @android.annotation.NonNull Parcelable.Creator<KeepalivePacketData> CREATOR = - new Parcelable.Creator<KeepalivePacketData>() { - public KeepalivePacketData createFromParcel(Parcel in) { - return new KeepalivePacketData(in); - } - - public KeepalivePacketData[] newArray(int size) { - return new KeepalivePacketData[size]; - } - }; - } diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 93dd2e4d7717..bf8b38fc7f84 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -30,7 +30,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index ed509cb3da34..ec773ef4a1e2 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -63,12 +63,21 @@ public final class LinkProperties implements Parcelable { private String mPrivateDnsServerName; private String mDomains; private ArrayList<RouteInfo> mRoutes = new ArrayList<>(); + private Inet4Address mDhcpServerAddress; private ProxyInfo mHttpProxy; private int mMtu; // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max" private String mTcpBufferSizes; private IpPrefix mNat64Prefix; private boolean mWakeOnLanSupported; + private Uri mCaptivePortalApiUrl; + private CaptivePortalData mCaptivePortalData; + + /** + * Indicates whether parceling should preserve fields that are set based on permissions of + * the process receiving the {@link LinkProperties}. + */ + private final transient boolean mParcelSensitiveFields; private static final int MIN_MTU = 68; private static final int MIN_MTU_V6 = 1280; @@ -173,6 +182,7 @@ public final class LinkProperties implements Parcelable { * Constructs a new {@code LinkProperties} with default values. */ public LinkProperties() { + mParcelSensitiveFields = false; } /** @@ -181,25 +191,32 @@ public final class LinkProperties implements Parcelable { @SystemApi @TestApi public LinkProperties(@Nullable LinkProperties source) { - if (source != null) { - mIfaceName = source.mIfaceName; - mLinkAddresses.addAll(source.mLinkAddresses); - mDnses.addAll(source.mDnses); - mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses); - mUsePrivateDns = source.mUsePrivateDns; - mPrivateDnsServerName = source.mPrivateDnsServerName; - mPcscfs.addAll(source.mPcscfs); - mDomains = source.mDomains; - mRoutes.addAll(source.mRoutes); - mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy); - for (LinkProperties l: source.mStackedLinks.values()) { - addStackedLink(l); - } - setMtu(source.mMtu); - mTcpBufferSizes = source.mTcpBufferSizes; - mNat64Prefix = source.mNat64Prefix; - mWakeOnLanSupported = source.mWakeOnLanSupported; + this(source, false /* parcelSensitiveFields */); + } + + private LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) { + mParcelSensitiveFields = parcelSensitiveFields; + if (source == null) return; + mIfaceName = source.mIfaceName; + mLinkAddresses.addAll(source.mLinkAddresses); + mDnses.addAll(source.mDnses); + mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses); + mUsePrivateDns = source.mUsePrivateDns; + mPrivateDnsServerName = source.mPrivateDnsServerName; + mPcscfs.addAll(source.mPcscfs); + mDomains = source.mDomains; + mRoutes.addAll(source.mRoutes); + mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy); + for (LinkProperties l: source.mStackedLinks.values()) { + addStackedLink(l); } + setMtu(source.mMtu); + setDhcpServerAddress(source.getDhcpServerAddress()); + mTcpBufferSizes = source.mTcpBufferSizes; + mNat64Prefix = source.mNat64Prefix; + mWakeOnLanSupported = source.mWakeOnLanSupported; + mCaptivePortalApiUrl = source.mCaptivePortalApiUrl; + mCaptivePortalData = source.mCaptivePortalData; } /** @@ -460,6 +477,24 @@ public final class LinkProperties implements Parcelable { } /** + * Set DHCP server address. + * + * @param serverAddress the server address to set. + */ + public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) { + mDhcpServerAddress = serverAddress; + } + + /** + * Get DHCP server address + * + * @return The current DHCP server address. + */ + public @Nullable Inet4Address getDhcpServerAddress() { + return mDhcpServerAddress; + } + + /** * Returns the private DNS server name that is in use. If not {@code null}, * private DNS is in strict mode. In this mode, applications should ensure * that all DNS queries are encrypted and sent to this hostname and that @@ -840,6 +875,11 @@ public final class LinkProperties implements Parcelable { * Clears this object to its initial state. */ public void clear() { + if (mParcelSensitiveFields) { + throw new UnsupportedOperationException( + "Cannot clear LinkProperties when parcelSensitiveFields is set"); + } + mIfaceName = null; mLinkAddresses.clear(); mDnses.clear(); @@ -851,9 +891,12 @@ public final class LinkProperties implements Parcelable { mHttpProxy = null; mStackedLinks.clear(); mMtu = 0; + mDhcpServerAddress = null; mTcpBufferSizes = null; mNat64Prefix = null; mWakeOnLanSupported = false; + mCaptivePortalApiUrl = null; + mCaptivePortalData = null; } /** @@ -919,6 +962,19 @@ public final class LinkProperties implements Parcelable { resultJoiner.add("WakeOnLanSupported: true"); } + if (mDhcpServerAddress != null) { + resultJoiner.add("ServerAddress:"); + resultJoiner.add(mDhcpServerAddress.toString()); + } + + if (mCaptivePortalApiUrl != null) { + resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl); + } + + if (mCaptivePortalData != null) { + resultJoiner.add("CaptivePortalData: " + mCaptivePortalData); + } + if (mTcpBufferSizes != null) { resultJoiner.add("TcpBufferSizes:"); resultJoiner.add(mTcpBufferSizes); @@ -1273,6 +1329,17 @@ public final class LinkProperties implements Parcelable { } /** + * Compares this {@code LinkProperties} DHCP server address against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) { + return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress); + } + + /** * Compares this {@code LinkProperties} interface addresses against the target * * @param target LinkProperties to compare. @@ -1442,6 +1509,28 @@ public final class LinkProperties implements Parcelable { } /** + * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) { + return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl); + } + + /** + * Compares this {@code LinkProperties}'s CaptivePortalData against the target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalCaptivePortalData(LinkProperties target) { + return Objects.equals(mCaptivePortalData, target.mCaptivePortalData); + } + + /** * Set whether the network interface supports WakeOnLAN * * @param supported WakeOnLAN supported value @@ -1462,6 +1551,73 @@ public final class LinkProperties implements Parcelable { } /** + * Set the URL of the captive portal API endpoint to get more information about the network. + * @hide + */ + @SystemApi + @TestApi + public void setCaptivePortalApiUrl(@Nullable Uri url) { + mCaptivePortalApiUrl = url; + } + + /** + * Get the URL of the captive portal API endpoint to get more information about the network. + * + * <p>This is null unless the application has + * {@link android.Manifest.permission.NETWORK_SETTINGS} or + * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided + * the URL. + * @hide + */ + @SystemApi + @TestApi + @Nullable + public Uri getCaptivePortalApiUrl() { + return mCaptivePortalApiUrl; + } + + /** + * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis). + * @hide + */ + @SystemApi + @TestApi + public void setCaptivePortalData(@Nullable CaptivePortalData data) { + mCaptivePortalData = data; + } + + /** + * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis). + * + * <p>This is null unless the application has + * {@link android.Manifest.permission.NETWORK_SETTINGS} or + * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions. + * @hide + */ + @SystemApi + @TestApi + @Nullable + public CaptivePortalData getCaptivePortalData() { + return mCaptivePortalData; + } + + /** + * Create a copy of this {@link LinkProperties} that will preserve fields that were set + * based on the permissions of the process that received this {@link LinkProperties}. + * + * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as + * they should not be shared outside of the process that receives them without appropriate + * checks. + * @hide + */ + @SystemApi + @TestApi + @NonNull + public LinkProperties makeSensitiveFieldsParcelingCopy() { + return new LinkProperties(this, true /* parcelSensitiveFields */); + } + + /** * Compares this {@code LinkProperties} instance against the target * LinkProperties in {@code obj}. Two LinkPropertieses are equal if * all their fields are equal in values. @@ -1489,6 +1645,7 @@ public final class LinkProperties implements Parcelable { */ return isIdenticalInterfaceName(target) && isIdenticalAddresses(target) + && isIdenticalDhcpServerAddress(target) && isIdenticalDnses(target) && isIdenticalPrivateDns(target) && isIdenticalValidatedPrivateDnses(target) @@ -1499,7 +1656,9 @@ public final class LinkProperties implements Parcelable { && isIdenticalMtu(target) && isIdenticalTcpBufferSizes(target) && isIdenticalNat64Prefix(target) - && isIdenticalWakeOnLan(target); + && isIdenticalWakeOnLan(target) + && isIdenticalCaptivePortalApiUrl(target) + && isIdenticalCaptivePortalData(target); } /** @@ -1613,10 +1772,12 @@ public final class LinkProperties implements Parcelable { + mMtu * 51 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode()) + (mUsePrivateDns ? 57 : 0) + + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode()) + mPcscfs.size() * 67 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode()) + Objects.hash(mNat64Prefix) - + (mWakeOnLanSupported ? 71 : 0); + + (mWakeOnLanSupported ? 71 : 0) + + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData); } /** @@ -1635,6 +1796,7 @@ public final class LinkProperties implements Parcelable { dest.writeString(mPrivateDnsServerName); writeAddresses(dest, mPcscfs); dest.writeString(mDomains); + writeAddress(dest, mDhcpServerAddress); dest.writeInt(mMtu); dest.writeString(mTcpBufferSizes); dest.writeInt(mRoutes.size()); @@ -1654,6 +1816,8 @@ public final class LinkProperties implements Parcelable { dest.writeList(stackedLinks); dest.writeBoolean(mWakeOnLanSupported); + dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0); + dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0); } private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) { @@ -1663,8 +1827,9 @@ public final class LinkProperties implements Parcelable { } } - private static void writeAddress(@NonNull Parcel dest, @NonNull InetAddress addr) { - dest.writeByteArray(addr.getAddress()); + private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) { + byte[] addressBytes = (addr == null ? null : addr.getAddress()); + dest.writeByteArray(addressBytes); if (addr instanceof Inet6Address) { final Inet6Address v6Addr = (Inet6Address) addr; final boolean hasScopeId = v6Addr.getScopeId() != 0; @@ -1673,9 +1838,11 @@ public final class LinkProperties implements Parcelable { } } - @NonNull + @Nullable private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException { final byte[] addr = p.createByteArray(); + if (addr == null) return null; + if (addr.length == INET6_ADDR_LENGTH) { final boolean hasScopeId = p.readBoolean(); final int scopeId = hasScopeId ? p.readInt() : 0; @@ -1722,6 +1889,10 @@ public final class LinkProperties implements Parcelable { } catch (UnknownHostException e) { } } netProp.setDomains(in.readString()); + try { + netProp.setDhcpServerAddress((Inet4Address) InetAddress + .getByAddress(in.createByteArray())); + } catch (UnknownHostException e) { } netProp.setMtu(in.readInt()); netProp.setTcpBufferSizes(in.readString()); addressCount = in.readInt(); @@ -1738,6 +1909,9 @@ public final class LinkProperties implements Parcelable { netProp.addStackedLink(stackedLink); } netProp.setWakeOnLanSupported(in.readBoolean()); + + netProp.setCaptivePortalApiUrl(in.readParcelable(null)); + netProp.setCaptivePortalData(in.readParcelable(null)); return netProp; } diff --git a/core/java/android/net/LinkQualityInfo.java b/core/java/android/net/LinkQualityInfo.java index 2e6915ff4aa5..aa56cff50f63 100644 --- a/core/java/android/net/LinkQualityInfo.java +++ b/core/java/android/net/LinkQualityInfo.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java index 6a2031b4131d..5b38f78782a8 100644 --- a/core/java/android/net/LocalSocket.java +++ b/core/java/android/net/LocalSocket.java @@ -16,7 +16,8 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.Closeable; import java.io.FileDescriptor; import java.io.IOException; diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java index b066a15106af..e80e3a6f93ec 100644 --- a/core/java/android/net/LocalSocketImpl.java +++ b/core/java/android/net/LocalSocketImpl.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.system.ErrnoException; import android.system.Int32Ref; import android.system.Os; diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 87295142bec4..74c9aac05b41 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -19,7 +19,7 @@ package android.net; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/MobileLinkQualityInfo.java b/core/java/android/net/MobileLinkQualityInfo.java index a10a14d750d8..a65de6bb2908 100644 --- a/core/java/android/net/MobileLinkQualityInfo.java +++ b/core/java/android/net/MobileLinkQualityInfo.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; /** diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java index a77c244d6b40..bd39c13ba092 100644 --- a/core/java/android/net/NattKeepalivePacketData.java +++ b/core/java/android/net/NattKeepalivePacketData.java @@ -16,10 +16,11 @@ package android.net; -import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; -import static android.net.SocketKeepalive.ERROR_INVALID_PORT; +import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS; +import static android.net.InvalidPacketException.ERROR_INVALID_PORT; -import android.net.SocketKeepalive.InvalidPacketException; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.net.util.IpUtils; import android.os.Parcel; import android.os.Parcelable; @@ -31,17 +32,22 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; /** @hide */ +@SystemApi public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable { + private static final int IPV4_HEADER_LENGTH = 20; + private static final int UDP_HEADER_LENGTH = 8; + // This should only be constructed via static factory methods, such as // nattKeepalivePacket - private NattKeepalivePacketData(InetAddress srcAddress, int srcPort, - InetAddress dstAddress, int dstPort, byte[] data) throws + public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort, + @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws InvalidPacketException { super(srcAddress, srcPort, dstAddress, dstPort, data); } /** * Factory method to create Nat-T keepalive packet structure. + * @hide */ public static NattKeepalivePacketData nattKeepalivePacket( InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort) @@ -85,7 +91,7 @@ public final class NattKeepalivePacketData extends KeepalivePacketData implement } /** Write to parcel */ - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeString(srcAddress.getHostAddress()); out.writeString(dstAddress.getHostAddress()); out.writeInt(srcPort); @@ -93,7 +99,7 @@ public final class NattKeepalivePacketData extends KeepalivePacketData implement } /** Parcelable Creator */ - public static final Parcelable.Creator<NattKeepalivePacketData> CREATOR = + public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR = new Parcelable.Creator<NattKeepalivePacketData>() { public NattKeepalivePacketData createFromParcel(Parcel in) { final InetAddress srcAddress = diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index f12ba1367d98..8d1ab332ce12 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -19,7 +19,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.system.ErrnoException; diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index ff4bf2d3474c..7316dfa5d1c6 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -17,7 +17,7 @@ package android.net; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Bundle; @@ -43,11 +43,10 @@ import java.util.concurrent.atomic.AtomicBoolean; * * @hide */ -public abstract class NetworkAgent extends Handler { - // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown - // an exception. - public final int netId; +public abstract class NetworkAgent { + public final Network network; + private final Handler mHandler; private volatile AsyncChannel mAsyncChannel; private final String LOG_TAG; private static final boolean DBG = true; @@ -58,7 +57,7 @@ public abstract class NetworkAgent extends Handler { private static final long BW_REFRESH_MIN_WIN_MS = 500; private boolean mPollLceScheduled = false; private AtomicBoolean mPollLcePending = new AtomicBoolean(false); - public final int mFactorySerialNumber; + public final int mProviderId; private static final int BASE = Protocol.BASE_NETWORK_AGENT; @@ -219,25 +218,25 @@ public abstract class NetworkAgent extends Handler { // the entire tree. public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) { - this(looper, context, logTag, ni, nc, lp, score, null, NetworkFactory.SerialNumber.NONE); + this(looper, context, logTag, ni, nc, lp, score, null, NetworkProvider.ID_NONE); } public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, - NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { - this(looper, context, logTag, ni, nc, lp, score, misc, NetworkFactory.SerialNumber.NONE); + NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config) { + this(looper, context, logTag, ni, nc, lp, score, config, NetworkProvider.ID_NONE); } public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, - NetworkCapabilities nc, LinkProperties lp, int score, int factorySerialNumber) { - this(looper, context, logTag, ni, nc, lp, score, null, factorySerialNumber); + NetworkCapabilities nc, LinkProperties lp, int score, int providerId) { + this(looper, context, logTag, ni, nc, lp, score, null, providerId); } public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, - NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc, - int factorySerialNumber) { - super(looper); + NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config, + int providerId) { + mHandler = new NetworkAgentHandler(looper); LOG_TAG = logTag; mContext = context; - mFactorySerialNumber = factorySerialNumber; + mProviderId = providerId; if (ni == null || nc == null || lp == null) { throw new IllegalArgumentException(); } @@ -245,117 +244,124 @@ public abstract class NetworkAgent extends Handler { if (VDBG) log("Registering NetworkAgent"); ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); - netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), - new LinkProperties(lp), new NetworkCapabilities(nc), score, misc, - factorySerialNumber); + network = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(ni), + new LinkProperties(lp), new NetworkCapabilities(nc), score, config, + providerId); } - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { - if (mAsyncChannel != null) { - log("Received new connection while already connected!"); - } else { - if (VDBG) log("NetworkAgent fully connected"); - AsyncChannel ac = new AsyncChannel(); - ac.connected(null, this, msg.replyTo); - ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, - AsyncChannel.STATUS_SUCCESSFUL); - synchronized (mPreConnectedQueue) { - mAsyncChannel = ac; - for (Message m : mPreConnectedQueue) { - ac.sendMessage(m); + private class NetworkAgentHandler extends Handler { + NetworkAgentHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { + if (mAsyncChannel != null) { + log("Received new connection while already connected!"); + } else { + if (VDBG) log("NetworkAgent fully connected"); + AsyncChannel ac = new AsyncChannel(); + ac.connected(null, this, msg.replyTo); + ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, + AsyncChannel.STATUS_SUCCESSFUL); + synchronized (mPreConnectedQueue) { + mAsyncChannel = ac; + for (Message m : mPreConnectedQueue) { + ac.sendMessage(m); + } + mPreConnectedQueue.clear(); } - mPreConnectedQueue.clear(); } + break; } - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECT: { - if (VDBG) log("CMD_CHANNEL_DISCONNECT"); - if (mAsyncChannel != null) mAsyncChannel.disconnect(); - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { - if (DBG) log("NetworkAgent channel lost"); - // let the client know CS is done with us. - unwanted(); - synchronized (mPreConnectedQueue) { - mAsyncChannel = null; + case AsyncChannel.CMD_CHANNEL_DISCONNECT: { + if (VDBG) log("CMD_CHANNEL_DISCONNECT"); + if (mAsyncChannel != null) mAsyncChannel.disconnect(); + break; } - break; - } - case CMD_SUSPECT_BAD: { - log("Unhandled Message " + msg); - break; - } - case CMD_REQUEST_BANDWIDTH_UPDATE: { - long currentTimeMs = System.currentTimeMillis(); - if (VDBG) { - log("CMD_REQUEST_BANDWIDTH_UPDATE request received."); + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + if (DBG) log("NetworkAgent channel lost"); + // let the client know CS is done with us. + unwanted(); + synchronized (mPreConnectedQueue) { + mAsyncChannel = null; + } + break; } - if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { - mPollLceScheduled = false; - if (mPollLcePending.getAndSet(true) == false) { - pollLceData(); + case CMD_SUSPECT_BAD: { + log("Unhandled Message " + msg); + break; + } + case CMD_REQUEST_BANDWIDTH_UPDATE: { + long currentTimeMs = System.currentTimeMillis(); + if (VDBG) { + log("CMD_REQUEST_BANDWIDTH_UPDATE request received."); } - } else { - // deliver the request at a later time rather than discard it completely. - if (!mPollLceScheduled) { - long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS - - currentTimeMs + 1; - mPollLceScheduled = sendEmptyMessageDelayed( - CMD_REQUEST_BANDWIDTH_UPDATE, waitTime); + if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { + mPollLceScheduled = false; + if (!mPollLcePending.getAndSet(true)) { + pollLceData(); + } + } else { + // deliver the request at a later time rather than discard it completely. + if (!mPollLceScheduled) { + long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS + - currentTimeMs + 1; + mPollLceScheduled = sendEmptyMessageDelayed( + CMD_REQUEST_BANDWIDTH_UPDATE, waitTime); + } } + break; } - break; - } - case CMD_REPORT_NETWORK_STATUS: { - String redirectUrl = ((Bundle)msg.obj).getString(REDIRECT_URL_KEY); - if (VDBG) { - log("CMD_REPORT_NETWORK_STATUS(" + - (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + redirectUrl); + case CMD_REPORT_NETWORK_STATUS: { + String redirectUrl = ((Bundle) msg.obj).getString(REDIRECT_URL_KEY); + if (VDBG) { + log("CMD_REPORT_NETWORK_STATUS(" + + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + + redirectUrl); + } + networkStatus(msg.arg1, redirectUrl); + break; + } + case CMD_SAVE_ACCEPT_UNVALIDATED: { + saveAcceptUnvalidated(msg.arg1 != 0); + break; + } + case CMD_START_SOCKET_KEEPALIVE: { + startSocketKeepalive(msg); + break; + } + case CMD_STOP_SOCKET_KEEPALIVE: { + stopSocketKeepalive(msg); + break; } - networkStatus(msg.arg1, redirectUrl); - break; - } - case CMD_SAVE_ACCEPT_UNVALIDATED: { - saveAcceptUnvalidated(msg.arg1 != 0); - break; - } - case CMD_START_SOCKET_KEEPALIVE: { - startSocketKeepalive(msg); - break; - } - case CMD_STOP_SOCKET_KEEPALIVE: { - stopSocketKeepalive(msg); - break; - } - case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { - ArrayList<Integer> thresholds = - ((Bundle) msg.obj).getIntegerArrayList("thresholds"); - // TODO: Change signal strength thresholds API to use an ArrayList<Integer> - // rather than convert to int[]. - int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0]; - for (int i = 0; i < intThresholds.length; i++) { - intThresholds[i] = thresholds.get(i); + case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { + ArrayList<Integer> thresholds = + ((Bundle) msg.obj).getIntegerArrayList("thresholds"); + // TODO: Change signal strength thresholds API to use an ArrayList<Integer> + // rather than convert to int[]. + int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0]; + for (int i = 0; i < intThresholds.length; i++) { + intThresholds[i] = thresholds.get(i); + } + setSignalStrengthThresholds(intThresholds); + break; + } + case CMD_PREVENT_AUTOMATIC_RECONNECT: { + preventAutomaticReconnect(); + break; + } + case CMD_ADD_KEEPALIVE_PACKET_FILTER: { + addKeepalivePacketFilter(msg); + break; + } + case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: { + removeKeepalivePacketFilter(msg); + break; } - setSignalStrengthThresholds(intThresholds); - break; - } - case CMD_PREVENT_AUTOMATIC_RECONNECT: { - preventAutomaticReconnect(); - break; - } - case CMD_ADD_KEEPALIVE_PACKET_FILTER: { - addKeepalivePacketFilter(msg); - break; - } - case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: { - removeKeepalivePacketFilter(msg); - break; } } } diff --git a/core/java/android/net/NetworkMisc.aidl b/core/java/android/net/NetworkAgentConfig.aidl index c65583fb530a..cb70bdd31260 100644 --- a/core/java/android/net/NetworkMisc.aidl +++ b/core/java/android/net/NetworkAgentConfig.aidl @@ -16,4 +16,4 @@ package android.net; -parcelable NetworkMisc; +parcelable NetworkAgentConfig; diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java new file mode 100644 index 000000000000..abc6b67efb11 --- /dev/null +++ b/core/java/android/net/NetworkAgentConfig.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +/** + * Allows a network transport to provide the system with policy and configuration information about + * a particular network when registering a {@link NetworkAgent}. This information cannot change once + * the agent is registered. + * + * @hide + */ +@SystemApi +public final class NetworkAgentConfig implements Parcelable { + + /** + * If the {@link Network} is a VPN, whether apps are allowed to bypass the + * VPN. This is set by a {@link VpnService} and used by + * {@link ConnectivityManager} when creating a VPN. + * + * @hide + */ + public boolean allowBypass; + + /** + * Set if the network was manually/explicitly connected to by the user either from settings + * or a 3rd party app. For example, turning on cell data is not explicit but tapping on a wifi + * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to + * connect to a particular access point is also explicit, though this may change in the future + * as we want apps to use the multinetwork apis. + * + * @hide + */ + public boolean explicitlySelected; + + /** + * Set if the user desires to use this network even if it is unvalidated. This field has meaning + * only if {@link explicitlySelected} is true. If it is, this field must also be set to the + * appropriate value based on previous user choice. + * + * @hide + */ + public boolean acceptUnvalidated; + + /** + * Whether the user explicitly set that this network should be validated even if presence of + * only partial internet connectivity. + * + * @hide + */ + public boolean acceptPartialConnectivity; + + /** + * Set to avoid surfacing the "Sign in to network" notification. + * if carrier receivers/apps are registered to handle the carrier-specific provisioning + * procedure, a carrier specific provisioning notification will be placed. + * only one notification should be displayed. This field is set based on + * which notification should be used for provisioning. + * + * @hide + */ + public boolean provisioningNotificationDisabled; + + /** + * + * @return whether the sign in to network notification is enabled by this configuration. + */ + public boolean isProvisioningNotificationEnabled() { + return !provisioningNotificationDisabled; + } + + /** + * For mobile networks, this is the subscriber ID (such as IMSI). + * + * @hide + */ + public String subscriberId; + + /** + * @return the subscriber ID, or null if none. + */ + @Nullable + public String getSubscriberId() { + return subscriberId; + } + + /** + * Set to skip 464xlat. This means the device will treat the network as IPv6-only and + * will not attempt to detect a NAT64 via RFC 7050 DNS lookups. + * + * @hide + */ + public boolean skip464xlat; + + /** + * @return whether NAT64 prefix detection is enabled. + */ + public boolean isNat64DetectionEnabled() { + return !skip464xlat; + } + + /** + * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network. + * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode. + * + * @hide + */ + public boolean hasShownBroken; + + /** @hide */ + public NetworkAgentConfig() { + } + + /** @hide */ + public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) { + if (nac != null) { + allowBypass = nac.allowBypass; + explicitlySelected = nac.explicitlySelected; + acceptUnvalidated = nac.acceptUnvalidated; + subscriberId = nac.subscriberId; + provisioningNotificationDisabled = nac.provisioningNotificationDisabled; + skip464xlat = nac.skip464xlat; + } + } + + /** + * Builder class to facilitate constructing {@link NetworkAgentConfig} objects. + */ + public static class Builder { + private final NetworkAgentConfig mConfig = new NetworkAgentConfig(); + + /** + * Sets the subscriber ID for this network. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setSubscriberId(@Nullable String subscriberId) { + mConfig.subscriberId = subscriberId; + return this; + } + + /** + * Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power + * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder disableNat64Detection() { + mConfig.skip464xlat = true; + return this; + } + + /** + * Disables the "Sign in to network" notification. Used if the network transport will + * perform its own carrier-specific provisioning procedure. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder disableProvisioningNotification() { + mConfig.provisioningNotificationDisabled = true; + return this; + } + + /** + * Returns the constructed {@link NetworkAgentConfig} object. + */ + @NonNull + public NetworkAgentConfig build() { + return mConfig; + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(allowBypass ? 1 : 0); + out.writeInt(explicitlySelected ? 1 : 0); + out.writeInt(acceptUnvalidated ? 1 : 0); + out.writeString(subscriberId); + out.writeInt(provisioningNotificationDisabled ? 1 : 0); + out.writeInt(skip464xlat ? 1 : 0); + } + + public static final @NonNull Creator<NetworkAgentConfig> CREATOR = + new Creator<NetworkAgentConfig>() { + @Override + public NetworkAgentConfig createFromParcel(Parcel in) { + NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig(); + networkAgentConfig.allowBypass = in.readInt() != 0; + networkAgentConfig.explicitlySelected = in.readInt() != 0; + networkAgentConfig.acceptUnvalidated = in.readInt() != 0; + networkAgentConfig.subscriberId = in.readString(); + networkAgentConfig.provisioningNotificationDisabled = in.readInt() != 0; + networkAgentConfig.skip464xlat = in.readInt() != 0; + return networkAgentConfig; + } + + @Override + public NetworkAgentConfig[] newArray(int size) { + return new NetworkAgentConfig[size]; + } + }; +} diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 421e61b76fab..8ebd1392240d 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.ConnectivityManager.NetworkCallback; import android.os.Build; import android.os.Parcel; @@ -587,15 +587,14 @@ public final class NetworkCapabilities implements Parcelable { } /** - * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are - * typically provided by restricted networks. + * Deduces that all the capabilities it provides are typically provided by restricted networks + * or not. * - * TODO: consider: - * - Renaming it to guessRestrictedCapability and make it set the - * restricted capability bit in addition to clearing it. + * @return {@code true} if the network should be restricted. * @hide */ - public void maybeMarkCapabilitiesRestricted() { + @SystemApi + public boolean deduceRestrictedCapability() { // Check if we have any capability that forces the network to be restricted. final boolean forceRestrictedCapability = (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0; @@ -609,8 +608,17 @@ public final class NetworkCapabilities implements Parcelable { final boolean hasRestrictedCapabilities = (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0; - if (forceRestrictedCapability - || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities)) { + return forceRestrictedCapability + || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities); + } + + /** + * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted. + * + * @hide + */ + public void maybeMarkCapabilitiesRestricted() { + if (deduceRestrictedCapability()) { removeCapability(NET_CAPABILITY_NOT_RESTRICTED); } } @@ -1275,6 +1283,7 @@ public final class NetworkCapabilities implements Parcelable { * Gets the SSID of this network, or null if none or unknown. * @hide */ + @SystemApi public @Nullable String getSSID() { return mSSID; } diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java index 5b1d12c603b4..e27103755e6d 100644 --- a/core/java/android/net/NetworkFactory.java +++ b/core/java/android/net/NetworkFactory.java @@ -16,7 +16,8 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; @@ -27,7 +28,6 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.AsyncChannel; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Protocol; @@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicInteger; * @hide **/ public class NetworkFactory extends Handler { - /** @hide */ + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public static class SerialNumber { // Guard used by no network factory. public static final int NONE = -1; @@ -91,8 +91,8 @@ public class NetworkFactory extends Handler { * with the same NetworkRequest but an updated score. * Also, network conditions may change for this bearer * allowing for a better score in the future. - * msg.arg2 = the serial number of the factory currently responsible for the - * NetworkAgent handling this request, or SerialNumber.NONE if none. + * msg.arg2 = the ID of the NetworkProvider currently responsible for the + * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. */ public static final int CMD_REQUEST_NETWORK = BASE; @@ -115,16 +115,8 @@ public class NetworkFactory extends Handler { */ private static final int CMD_SET_FILTER = BASE + 3; - /** - * Sent by NetworkFactory to ConnectivityService to indicate that a request is - * unfulfillable. - * @see #releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest). - */ - public static final int EVENT_UNFULFILLABLE_REQUEST = BASE + 4; - private final Context mContext; private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>(); - private AsyncChannel mAsyncChannel; private final String LOG_TAG; private final SparseArray<NetworkRequestInfo> mNetworkRequests = @@ -135,7 +127,8 @@ public class NetworkFactory extends Handler { private int mRefCount = 0; private Messenger mMessenger = null; - private int mSerialNumber; + private NetworkProvider mProvider = null; + private int mProviderId; @UnsupportedAppUsage public NetworkFactory(Looper looper, Context context, String logTag, @@ -147,55 +140,43 @@ public class NetworkFactory extends Handler { } public void register() { - if (DBG) log("Registering NetworkFactory"); - if (mMessenger == null) { - mMessenger = new Messenger(this); - mSerialNumber = ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, - LOG_TAG); + if (mProvider != null) { + Log.e(LOG_TAG, "Ignoring attempt to register already-registered NetworkFactory"); + return; } + if (DBG) log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest((NetworkRequest) request, score, servingProviderId); + } + + @Override + public void onRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + mMessenger = new Messenger(this); + mProviderId = ConnectivityManager.from(mContext).registerNetworkProvider(mProvider); } public void unregister() { - if (DBG) log("Unregistering NetworkFactory"); - if (mMessenger != null) { - ConnectivityManager.from(mContext).unregisterNetworkFactory(mMessenger); - mMessenger = null; + if (mProvider == null) { + Log.e(LOG_TAG, "Ignoring attempt to unregister unregistered NetworkFactory"); + return; } + if (DBG) log("Unregistering NetworkFactory"); + + ConnectivityManager.from(mContext).unregisterNetworkProvider(mProvider); + mProvider = null; } @Override public void handleMessage(Message msg) { switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { - if (mAsyncChannel != null) { - log("Received new connection while already connected!"); - break; - } - if (VDBG) log("NetworkFactory fully connected"); - AsyncChannel ac = new AsyncChannel(); - ac.connected(null, this, msg.replyTo); - ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, - AsyncChannel.STATUS_SUCCESSFUL); - mAsyncChannel = ac; - for (Message m : mPreConnectedQueue) { - ac.sendMessage(m); - } - mPreConnectedQueue.clear(); - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECT: { - if (VDBG) log("CMD_CHANNEL_DISCONNECT"); - if (mAsyncChannel != null) { - mAsyncChannel.disconnect(); - mAsyncChannel = null; - } - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { - if (DBG) log("NetworkFactory channel lost"); - mAsyncChannel = null; - break; - } case CMD_REQUEST_NETWORK: { handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); break; @@ -219,13 +200,13 @@ public class NetworkFactory extends Handler { public final NetworkRequest request; public int score; public boolean requested; // do we have a request outstanding, limited by score - public int factorySerialNumber; + public int providerId; - NetworkRequestInfo(NetworkRequest request, int score, int factorySerialNumber) { + NetworkRequestInfo(NetworkRequest request, int score, int providerId) { this.request = request; this.score = score; this.requested = false; - this.factorySerialNumber = factorySerialNumber; + this.providerId = providerId; } @Override @@ -240,8 +221,6 @@ public class NetworkFactory extends Handler { * * @param request the request to handle. * @param score the score of the NetworkAgent currently satisfying this request. - * @param servingFactorySerialNumber the serial number of the NetworkFactory that - * created the NetworkAgent currently satisfying this request. */ // TODO : remove this method. It is a stopgap measure to help sheperding a number // of dependent changes that would conflict throughout the automerger graph. Having this @@ -249,7 +228,7 @@ public class NetworkFactory extends Handler { // the entire tree. @VisibleForTesting protected void handleAddRequest(NetworkRequest request, int score) { - handleAddRequest(request, score, SerialNumber.NONE); + handleAddRequest(request, score, NetworkProvider.ID_NONE); } /** @@ -258,27 +237,26 @@ public class NetworkFactory extends Handler { * * @param request the request to handle. * @param score the score of the NetworkAgent currently satisfying this request. - * @param servingFactorySerialNumber the serial number of the NetworkFactory that - * created the NetworkAgent currently satisfying this request. + * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent + * currently satisfying this request. */ @VisibleForTesting - protected void handleAddRequest(NetworkRequest request, int score, - int servingFactorySerialNumber) { + protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { NetworkRequestInfo n = mNetworkRequests.get(request.requestId); if (n == null) { if (DBG) { log("got request " + request + " with score " + score - + " and serial " + servingFactorySerialNumber); + + " and providerId " + servingProviderId); } - n = new NetworkRequestInfo(request, score, servingFactorySerialNumber); + n = new NetworkRequestInfo(request, score, servingProviderId); mNetworkRequests.put(n.request.requestId, n); } else { if (VDBG) { log("new score " + score + " for exisiting request " + request - + " with serial " + servingFactorySerialNumber); + + " and providerId " + servingProviderId); } n.score = score; - n.factorySerialNumber = servingFactorySerialNumber; + n.providerId = servingProviderId; } if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); @@ -333,8 +311,8 @@ public class NetworkFactory extends Handler { log(" n.requests = " + n.requested); log(" n.score = " + n.score); log(" mScore = " + mScore); - log(" n.factorySerialNumber = " + n.factorySerialNumber); - log(" mSerialNumber = " + mSerialNumber); + log(" n.providerId = " + n.providerId); + log(" mProviderId = " + mProviderId); } if (shouldNeedNetworkFor(n)) { if (VDBG) log(" needNetworkFor"); @@ -355,7 +333,7 @@ public class NetworkFactory extends Handler { // If the score of this request is higher or equal to that of this factory and some // other factory is responsible for it, then this factory should not track the request // because it has no hope of satisfying it. - && (n.score < mScore || n.factorySerialNumber == mSerialNumber) + && (n.score < mScore || n.providerId == mProviderId) // If this factory can't satisfy the capability needs of this request, then it // should not be tracked. && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) @@ -373,7 +351,7 @@ public class NetworkFactory extends Handler { // assigned to the factory // - This factory can't satisfy the capability needs of the request // - The concrete implementation of the factory rejects the request - && ((n.score > mScore && n.factorySerialNumber != mSerialNumber) + && ((n.score > mScore && n.providerId != mProviderId) || !n.request.networkCapabilities.satisfiedByNetworkCapabilities( mCapabilityFilter) || !acceptRequest(n.request, n.score)); @@ -408,12 +386,7 @@ public class NetworkFactory extends Handler { protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { post(() -> { if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); - Message msg = obtainMessage(EVENT_UNFULFILLABLE_REQUEST, r); - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(msg); - } else { - mPreConnectedQueue.add(msg); - } + ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(r); }); } @@ -444,8 +417,13 @@ public class NetworkFactory extends Handler { return mNetworkRequests.size(); } + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public int getSerialNumber() { - return mSerialNumber; + return mProviderId; + } + + public int getProviderId() { + return mProviderId; } protected void log(String s) { @@ -465,8 +443,8 @@ public class NetworkFactory extends Handler { @Override public String toString() { - StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mSerialNumber=") - .append(mSerialNumber).append(", ScoreFilter=") + StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mProviderId=") + .append(mProviderId).append(", ScoreFilter=") .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) .append("}"); diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 92f105f77172..d0c536316527 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -17,7 +17,7 @@ package android.net; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java deleted file mode 100644 index 4ad52d5aa1bc..000000000000 --- a/core/java/android/net/NetworkMisc.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * A grab-bag of information (metadata, policies, properties, etc) about a - * {@link Network}. Since this contains PII, it should not be sent outside the - * system. - * - * @hide - */ -public class NetworkMisc implements Parcelable { - - /** - * If the {@link Network} is a VPN, whether apps are allowed to bypass the - * VPN. This is set by a {@link VpnService} and used by - * {@link ConnectivityManager} when creating a VPN. - */ - public boolean allowBypass; - - /** - * Set if the network was manually/explicitly connected to by the user either from settings - * or a 3rd party app. For example, turning on cell data is not explicit but tapping on a wifi - * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to - * connect to a particular access point is also explicit, though this may change in the future - * as we want apps to use the multinetwork apis. - */ - public boolean explicitlySelected; - - /** - * Set if the user desires to use this network even if it is unvalidated. This field has meaning - * only if {@link explicitlySelected} is true. If it is, this field must also be set to the - * appropriate value based on previous user choice. - */ - public boolean acceptUnvalidated; - - /** - * Whether the user explicitly set that this network should be validated even if presence of - * only partial internet connectivity. - */ - public boolean acceptPartialConnectivity; - - /** - * Set to avoid surfacing the "Sign in to network" notification. - * if carrier receivers/apps are registered to handle the carrier-specific provisioning - * procedure, a carrier specific provisioning notification will be placed. - * only one notification should be displayed. This field is set based on - * which notification should be used for provisioning. - */ - public boolean provisioningNotificationDisabled; - - /** - * For mobile networks, this is the subscriber ID (such as IMSI). - */ - public String subscriberId; - - /** - * Set to skip 464xlat. This means the device will treat the network as IPv6-only and - * will not attempt to detect a NAT64 via RFC 7050 DNS lookups. - */ - public boolean skip464xlat; - - /** - * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network. - * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode. - */ - public boolean hasShownBroken; - - public NetworkMisc() { - } - - public NetworkMisc(NetworkMisc nm) { - if (nm != null) { - allowBypass = nm.allowBypass; - explicitlySelected = nm.explicitlySelected; - acceptUnvalidated = nm.acceptUnvalidated; - subscriberId = nm.subscriberId; - provisioningNotificationDisabled = nm.provisioningNotificationDisabled; - skip464xlat = nm.skip464xlat; - } - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(allowBypass ? 1 : 0); - out.writeInt(explicitlySelected ? 1 : 0); - out.writeInt(acceptUnvalidated ? 1 : 0); - out.writeString(subscriberId); - out.writeInt(provisioningNotificationDisabled ? 1 : 0); - out.writeInt(skip464xlat ? 1 : 0); - } - - public static final @android.annotation.NonNull Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() { - @Override - public NetworkMisc createFromParcel(Parcel in) { - NetworkMisc networkMisc = new NetworkMisc(); - networkMisc.allowBypass = in.readInt() != 0; - networkMisc.explicitlySelected = in.readInt() != 0; - networkMisc.acceptUnvalidated = in.readInt() != 0; - networkMisc.subscriberId = in.readString(); - networkMisc.provisioningNotificationDisabled = in.readInt() != 0; - networkMisc.skip464xlat = in.readInt() != 0; - return networkMisc; - } - - @Override - public NetworkMisc[] newArray(int size) { - return new NetworkMisc[size]; - } - }; -} diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 33baebbbe857..4f05c9bbb2e3 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index bf272625e713..de962f8f25e3 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -19,8 +19,8 @@ package android.net; import static android.content.pm.PackageManager.GET_SIGNATURES; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -31,6 +31,7 @@ import android.net.wifi.WifiInfo; import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; +import android.telephony.SubscriptionPlan; import android.util.DebugUtils; import android.util.Pair; import android.util.Range; @@ -380,6 +381,8 @@ public class NetworkPolicyManager { @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { } @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { } @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { } - @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) { } + @Override public void onSubscriptionOverride(int subId, int overrideMask, + int overrideValue) { } + @Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { } } } diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java new file mode 100644 index 000000000000..2c0e4aa700b1 --- /dev/null +++ b/core/java/android/net/NetworkProvider.java @@ -0,0 +1,166 @@ +/* + * 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.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.util.Log; + +/** + * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device + * to networks and makes them available to to the core network stack by creating + * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted + * with via networking APIs such as {@link ConnectivityManager}. + * + * Subclasses should implement {@link #onNetworkRequested} and {@link #onRequestWithdrawn} to + * receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the + * best (highest-scoring) network for any request is generally not used by the system, and torn + * down. + * + * @hide + */ +@SystemApi +public class NetworkProvider { + /** + * {@code providerId} value that indicates the absence of a provider. It is the providerId of + * any NetworkProvider that is not currently registered, and of any NetworkRequest that is not + * currently being satisfied by a network. + */ + public static final int ID_NONE = -1; + + /** + * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any + * provider, so they use this constant for clarity instead of NONE. + * @hide only used by ConnectivityService. + */ + public static final int ID_VPN = -2; + + /** + * The first providerId value that will be allocated. + * @hide only used by ConnectivityService. + */ + public static final int FIRST_PROVIDER_ID = 1; + + /** @hide only used by ConnectivityService */ + public static final int CMD_REQUEST_NETWORK = 1; + /** @hide only used by ConnectivityService */ + public static final int CMD_CANCEL_REQUEST = 2; + + private final Messenger mMessenger; + private final String mName; + private final ConnectivityManager mCm; + + private int mProviderId = ID_NONE; + + /** + * Constructs a new NetworkProvider. + * + * @param looper the Looper on which to run {@link #onNetworkRequested} and + * {@link #onRequestWithdrawn}. + * @param name the name of the listener, used only for debugging. + * + * @hide + */ + @SystemApi + public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) { + mCm = ConnectivityManager.from(context); + + Handler handler = new Handler(looper) { + @Override + public void handleMessage(Message m) { + switch (m.what) { + case CMD_REQUEST_NETWORK: + onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2); + break; + case CMD_CANCEL_REQUEST: + onRequestWithdrawn((NetworkRequest) m.obj); + break; + default: + Log.e(mName, "Unhandled message: " + m.what); + } + } + }; + mMessenger = new Messenger(handler); + mName = name; + } + + // TODO: consider adding a register() method so ConnectivityManager does not need to call this. + public @Nullable Messenger getMessenger() { + return mMessenger; + } + + public @NonNull String getName() { + return mName; + } + + /** + * Returns the ID of this provider. This is known only once the provider is registered via + * {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}. + * This ID must be used when registering any {@link NetworkAgent}s. + */ + public int getProviderId() { + return mProviderId; + } + + /** @hide */ + public void setProviderId(int providerId) { + mProviderId = providerId; + } + + /** + * Called when a NetworkRequest is received. The request may be a new request or an existing + * request with a different score. + * + * @param request the NetworkRequest being received + * @param score the score of the network currently satisfying the request, or 0 if none. + * @param providerId the ID of the provider that created the network currently satisfying this + * request, or {@link #ID_NONE} if none. + * + * @hide + */ + @SystemApi + public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {} + + /** + * Called when a NetworkRequest is withdrawn. + * @hide + */ + @SystemApi + public void onRequestWithdrawn(@NonNull NetworkRequest request) {} + + /** + * Asserts that no provider will ever be able to satisfy the specified request. The provider + * must only call this method if it knows that it is the only provider on the system capable of + * satisfying this request, and that the request cannot be satisfied. The application filing the + * request will receive an {@link NetworkCallback#onUnavailable()} callback. + * + * @param request the request that cannot be fulfilled + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { + mCm.declareNetworkRequestUnfulfillable(request); + } +} diff --git a/core/java/android/net/NetworkQuotaInfo.java b/core/java/android/net/NetworkQuotaInfo.java index a46cddeda2dd..2e52d9cd19ab 100644 --- a/core/java/android/net/NetworkQuotaInfo.java +++ b/core/java/android/net/NetworkQuotaInfo.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 471b23e04775..ee4379a85b6b 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.NetworkCapabilities.NetCapability; import android.net.NetworkCapabilities.Transport; import android.os.Build; @@ -247,9 +247,8 @@ public class NetworkRequest implements Parcelable { * removing even the capabilities that are set by default when the object is constructed. * * @return The builder to facilitate chaining. - * @hide */ - @UnsupportedAppUsage + @NonNull public Builder clearCapabilities() { mNetworkCapabilities.clearAll(); return this; @@ -301,22 +300,34 @@ public class NetworkRequest implements Parcelable { * this without a single transport set will generate an exception, as will * subsequently adding or removing transports after this is set. * </p> - * The interpretation of this {@code String} is bearer specific and bearers that use - * it should document their particulars. For example, Bluetooth may use some sort of - * device id while WiFi could used ssid and/or bssid. Cellular may use carrier spn. + * If the {@code networkSpecifier} is provided, it shall be interpreted as follows: + * <ul> + * <li>If the specifier can be parsed as an integer, it will be treated as a + * {@link android.net TelephonyNetworkSpecifier}, and the provided integer will be + * interpreted as a SubscriptionId. + * <li>If the value is an ethernet interface name, it will be treated as such. + * <li>For all other cases, the behavior is undefined. + * </ul> + * + * @param networkSpecifier A {@code String} of either a SubscriptionId in cellular + * network request or an ethernet interface name in ethernet + * network request. * - * @param networkSpecifier An {@code String} of opaque format used to specify the bearer - * specific network specifier where the bearer has a choice of - * networks. + * @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead. */ + @Deprecated public Builder setNetworkSpecifier(String networkSpecifier) { - /* - * A StringNetworkSpecifier does not accept null or empty ("") strings. When network - * specifiers were strings a null string and an empty string were considered equivalent. - * Hence no meaning is attached to a null or empty ("") string. - */ - return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null - : new StringNetworkSpecifier(networkSpecifier)); + try { + int subId = Integer.parseInt(networkSpecifier); + return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(subId).build()); + } catch (NumberFormatException nfe) { + // A StringNetworkSpecifier does not accept null or empty ("") strings. When network + // specifiers were strings a null string and an empty string were considered + // equivalent. Hence no meaning is attached to a null or empty ("") string. + return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null + : new StringNetworkSpecifier(networkSpecifier)); + } } /** @@ -456,6 +467,19 @@ public class NetworkRequest implements Parcelable { } /** + * Returns true iff. the capabilities requested in this NetworkRequest are satisfied by the + * provided {@link NetworkCapabilities}. + * + * @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not + * satisfy any request. + * @hide + */ + @SystemApi + public boolean satisfiedBy(@Nullable NetworkCapabilities nc) { + return networkCapabilities.satisfiedByNetworkCapabilities(nc); + } + + /** * @see Builder#addTransportType(int) */ public boolean hasTransport(@Transport int transportType) { diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java index f6dc52522cb2..c233ec0e52cf 100644 --- a/core/java/android/net/NetworkScoreManager.java +++ b/core/java/android/net/NetworkScoreManager.java @@ -163,27 +163,26 @@ public class NetworkScoreManager { public static final String EXTRA_NEW_SCORER = "newScorer"; /** @hide */ - @IntDef({CACHE_FILTER_NONE, CACHE_FILTER_CURRENT_NETWORK, CACHE_FILTER_SCAN_RESULTS}) + @IntDef({SCORE_FILTER_NONE, SCORE_FILTER_CURRENT_NETWORK, SCORE_FILTER_SCAN_RESULTS}) @Retention(RetentionPolicy.SOURCE) - public @interface CacheUpdateFilter {} + public @interface ScoreUpdateFilter {} /** - * Do not filter updates sent to the cache. - * @hide + * Do not filter updates sent to the {@link NetworkScoreCallback}]. */ - public static final int CACHE_FILTER_NONE = 0; + public static final int SCORE_FILTER_NONE = 0; /** - * Only send cache updates when the network matches the connected network. - * @hide + * Only send updates to the {@link NetworkScoreCallback} when the network matches the connected + * network. */ - public static final int CACHE_FILTER_CURRENT_NETWORK = 1; + public static final int SCORE_FILTER_CURRENT_NETWORK = 1; /** - * Only send cache updates when the network is part of the current scan result set. - * @hide + * Only send updates to the {@link NetworkScoreCallback} when the network is part of the + * current scan result set. */ - public static final int CACHE_FILTER_SCAN_RESULTS = 2; + public static final int SCORE_FILTER_SCAN_RESULTS = 2; /** @hide */ @IntDef({RECOMMENDATIONS_ENABLED_FORCED_OFF, RECOMMENDATIONS_ENABLED_OFF, @@ -404,13 +403,13 @@ public class NetworkScoreManager { * @throws SecurityException if the caller does not hold the * {@link permission#REQUEST_NETWORK_SCORES} permission. * @throws IllegalArgumentException if a score cache is already registered for this type. - * @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE. + * @deprecated equivalent to registering for cache updates with {@link #SCORE_FILTER_NONE}. * @hide */ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) @Deprecated // migrate to registerNetworkScoreCache(int, INetworkScoreCache, int) public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) { - registerNetworkScoreCache(networkType, scoreCache, CACHE_FILTER_NONE); + registerNetworkScoreCache(networkType, scoreCache, SCORE_FILTER_NONE); } /** @@ -418,7 +417,7 @@ public class NetworkScoreManager { * * @param networkType the type of network this cache can handle. See {@link NetworkKey#type} * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores - * @param filterType the {@link CacheUpdateFilter} to apply + * @param filterType the {@link ScoreUpdateFilter} to apply * @throws SecurityException if the caller does not hold the * {@link permission#REQUEST_NETWORK_SCORES} permission. * @throws IllegalArgumentException if a score cache is already registered for this type. @@ -426,7 +425,7 @@ public class NetworkScoreManager { */ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache, - @CacheUpdateFilter int filterType) { + @ScoreUpdateFilter int filterType) { try { mService.registerNetworkScoreCache(networkType, scoreCache, filterType); } catch (RemoteException e) { @@ -510,7 +509,7 @@ public class NetworkScoreManager { * Register a network score callback. * * @param networkType the type of network this cache can handle. See {@link NetworkKey#type} - * @param filterType the {@link CacheUpdateFilter} to apply + * @param filterType the {@link ScoreUpdateFilter} to apply * @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the * scores change. * @param executor The executor on which to execute the callbacks. @@ -522,7 +521,7 @@ public class NetworkScoreManager { @SystemApi @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType, - @CacheUpdateFilter int filterType, + @ScoreUpdateFilter int filterType, @NonNull @CallbackExecutor Executor executor, @NonNull NetworkScoreCallback callback) throws SecurityException { if (callback == null || executor == null) { diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java index 2bc3eb56ec2d..cf31d217c967 100644 --- a/core/java/android/net/NetworkSpecifier.java +++ b/core/java/android/net/NetworkSpecifier.java @@ -16,6 +16,9 @@ package android.net; +import android.annotation.Nullable; +import android.annotation.SystemApi; + /** * Describes specific properties of a requested network for use in a {@link NetworkRequest}. * @@ -31,7 +34,8 @@ public abstract class NetworkSpecifier { * * @hide */ - public abstract boolean satisfiedBy(NetworkSpecifier other); + @SystemApi + public abstract boolean satisfiedBy(@Nullable NetworkSpecifier other); /** * Optional method which can be overridden by concrete implementations of NetworkSpecifier to @@ -45,6 +49,7 @@ public abstract class NetworkSpecifier { * * @hide */ + @SystemApi public void assertValidFromUid(int requestorUid) { // empty } @@ -68,6 +73,8 @@ public abstract class NetworkSpecifier { * * @hide */ + @SystemApi + @Nullable public NetworkSpecifier redact() { // TODO (b/122160111): convert default to null once all platform NetworkSpecifiers // implement this method. diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index 292cf50ac4ae..e44961528708 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 6c7aa1379fb1..96d7a80886a5 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -19,7 +19,10 @@ package android.net; import static android.os.Process.CLAT_UID; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -48,59 +51,104 @@ import java.util.function.Predicate; * @hide */ // @NotThreadSafe -public class NetworkStats implements Parcelable { +@SystemApi +public final class NetworkStats implements Parcelable { private static final String TAG = "NetworkStats"; + /** {@link #iface} value when interface details unavailable. */ - public static final String IFACE_ALL = null; + @SuppressLint("CompileTimeConstant") + @Nullable public static final String IFACE_ALL = null; + /** + * Virtual network interface for video telephony. This is for VT data usage counting + * purpose. + */ + public static final String IFACE_VT = "vt_data0"; + /** {@link #uid} value when UID details unavailable. */ public static final int UID_ALL = -1; - /** {@link #tag} value matching any tag. */ + /** Special UID value for data usage by tethering. */ + public static final int UID_TETHERING = -5; + + /** + * {@link #tag} value matching any tag. + * @hide + */ // TODO: Rename TAG_ALL to TAG_ANY. public static final int TAG_ALL = -1; - /** {@link #set} value for all sets combined, not including debug sets. */ + /** + * {@link #set} value for all sets combined, not including debug sets. + * @hide + */ public static final int SET_ALL = -1; /** {@link #set} value where background data is accounted. */ public static final int SET_DEFAULT = 0; /** {@link #set} value where foreground data is accounted. */ public static final int SET_FOREGROUND = 1; - /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */ + /** + * All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. + * @hide + */ public static final int SET_DEBUG_START = 1000; - /** Debug {@link #set} value when the VPN stats are moved in. */ + /** + * Debug {@link #set} value when the VPN stats are moved in. + * @hide + */ public static final int SET_DBG_VPN_IN = 1001; - /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ + /** + * Debug {@link #set} value when the VPN stats are moved out of a vpn UID. + * @hide + */ public static final int SET_DBG_VPN_OUT = 1002; - /** Include all interfaces when filtering */ - public static final String[] INTERFACES_ALL = null; + /** + * Include all interfaces when filtering + * @hide + */ + public @Nullable static final String[] INTERFACES_ALL = null; /** {@link #tag} value for total data across all tags. */ // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #metered} value to account for all metered states. */ + /** + * {@link #metered} value to account for all metered states. + * @hide + */ public static final int METERED_ALL = -1; /** {@link #metered} value where native, unmetered data is accounted. */ public static final int METERED_NO = 0; /** {@link #metered} value where metered data is accounted. */ public static final int METERED_YES = 1; - /** {@link #roaming} value to account for all roaming states. */ + /** + * {@link #roaming} value to account for all roaming states. + * @hide + */ public static final int ROAMING_ALL = -1; /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; - /** {@link #onDefaultNetwork} value to account for all default network states. */ + /** + * {@link #onDefaultNetwork} value to account for all default network states. + * @hide + */ public static final int DEFAULT_NETWORK_ALL = -1; /** {@link #onDefaultNetwork} value to account for usage while not the default network. */ public static final int DEFAULT_NETWORK_NO = 0; /** {@link #onDefaultNetwork} value to account for usage while the default network. */ public static final int DEFAULT_NETWORK_YES = 1; - /** Denotes a request for stats at the interface level. */ + /** + * Denotes a request for stats at the interface level. + * @hide + */ public static final int STATS_PER_IFACE = 0; - /** Denotes a request for stats at the interface and UID level. */ + /** + * Denotes a request for stats at the interface and UID level. + * @hide + */ public static final int STATS_PER_UID = 1; private static final String CLATD_INTERFACE_PREFIX = "v4-"; @@ -144,60 +192,78 @@ public class NetworkStats implements Parcelable { @UnsupportedAppUsage private long[] operations; + /** @hide */ + @SystemApi public static class Entry { + /** @hide */ @UnsupportedAppUsage public String iface; + /** @hide */ @UnsupportedAppUsage public int uid; + /** @hide */ @UnsupportedAppUsage public int set; + /** @hide */ @UnsupportedAppUsage public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of * getSummary(). + * @hide */ public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of * getSummary(). + * @hide */ public int roaming; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of * getSummary(). + * @hide */ public int defaultNetwork; + /** @hide */ @UnsupportedAppUsage public long rxBytes; + /** @hide */ @UnsupportedAppUsage public long rxPackets; + /** @hide */ @UnsupportedAppUsage public long txBytes; + /** @hide */ @UnsupportedAppUsage public long txPackets; + /** @hide */ + @UnsupportedAppUsage public long operations; + /** @hide */ @UnsupportedAppUsage public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } + /** @hide */ public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, operations); } + /** @hide */ public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, rxPackets, txBytes, txPackets, operations); } - public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + public Entry(@Nullable String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; @@ -214,15 +280,18 @@ public class NetworkStats implements Parcelable { this.operations = operations; } + /** @hide */ public boolean isNegative() { return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0; } + /** @hide */ public boolean isEmpty() { return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0 && operations == 0; } + /** @hide */ public void add(Entry another) { this.rxBytes += another.rxBytes; this.rxPackets += another.rxPackets; @@ -249,6 +318,7 @@ public class NetworkStats implements Parcelable { return builder.toString(); } + /** @hide */ @Override public boolean equals(Object o) { if (o instanceof Entry) { @@ -262,13 +332,13 @@ public class NetworkStats implements Parcelable { return false; } + /** @hide */ @Override public int hashCode() { return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface); } } - @UnsupportedAppUsage public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; @@ -292,6 +362,7 @@ public class NetworkStats implements Parcelable { } } + /** @hide */ @UnsupportedAppUsage public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); @@ -312,7 +383,7 @@ public class NetworkStats implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeLong(elapsedRealtime); dest.writeInt(size); dest.writeInt(capacity); @@ -330,19 +401,23 @@ public class NetworkStats implements Parcelable { dest.writeLongArray(operations); } + /** + * @hide + */ @Override public NetworkStats clone() { final NetworkStats clone = new NetworkStats(elapsedRealtime, size); NetworkStats.Entry entry = null; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - clone.addValues(entry); + clone.addEntry(entry); } return clone; } /** * Clear all data stored in this object. + * @hide */ public void clear() { this.capacity = 0; @@ -360,25 +435,28 @@ public class NetworkStats implements Parcelable { this.operations = EmptyArray.LONG; } + /** @hide */ @VisibleForTesting public NetworkStats addIfaceValues( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return addValues( + return addEntry( iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } + /** @hide */ @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes, + public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return addValues(new Entry( + return addEntry(new Entry( iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } + /** @hide */ @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, + public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return addValues(new Entry( + return addEntry(new Entry( iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets, txBytes, txPackets, operations)); } @@ -386,8 +464,9 @@ public class NetworkStats implements Parcelable { /** * Add new stats entry, copying from given {@link Entry}. The {@link Entry} * object can be recycled across multiple calls. + * @hide */ - public NetworkStats addValues(Entry entry) { + public NetworkStats addEntry(Entry entry) { if (size >= capacity) { final int newLength = Math.max(size, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); @@ -428,6 +507,7 @@ public class NetworkStats implements Parcelable { /** * Return specific stats entry. + * @hide */ @UnsupportedAppUsage public Entry getValues(int i, Entry recycle) { @@ -467,10 +547,12 @@ public class NetworkStats implements Parcelable { operations[dest] = operations[src]; } + /** @hide */ public long getElapsedRealtime() { return elapsedRealtime; } + /** @hide */ public void setElapsedRealtime(long time) { elapsedRealtime = time; } @@ -478,21 +560,25 @@ public class NetworkStats implements Parcelable { /** * Return age of this {@link NetworkStats} object with respect to * {@link SystemClock#elapsedRealtime()}. + * @hide */ public long getElapsedRealtimeAge() { return SystemClock.elapsedRealtime() - elapsedRealtime; } + /** @hide */ @UnsupportedAppUsage public int size() { return size; } + /** @hide */ @VisibleForTesting public int internalSize() { return capacity; } + /** @hide */ @Deprecated public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { @@ -501,6 +587,7 @@ public class NetworkStats implements Parcelable { txPackets, operations); } + /** @hide */ public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return combineValues(new Entry( @@ -509,16 +596,20 @@ public class NetworkStats implements Parcelable { /** * Combine given values with an existing row, or create a new row if - * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can - * also be used to subtract values from existing rows. + * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can + * also be used to subtract values from existing rows. This method mutates the referencing + * {@link NetworkStats} object. + * + * @param entry the {@link Entry} to combine. + * @return a reference to this mutated {@link NetworkStats} object. + * @hide */ - @UnsupportedAppUsage - public NetworkStats combineValues(Entry entry) { + public @NonNull NetworkStats combineValues(@NonNull Entry entry) { final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, entry.roaming, entry.defaultNetwork); if (i == -1) { // only create new entry when positive contribution - addValues(entry); + addEntry(entry); } else { rxBytes[i] += entry.rxBytes; rxPackets[i] += entry.rxPackets; @@ -530,10 +621,33 @@ public class NetworkStats implements Parcelable { } /** + * Add given values with an existing row, or create a new row if + * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can + * also be used to subtract values from existing rows. + * + * @param entry the {@link Entry} to add. + * @return a new constructed {@link NetworkStats} object that contains the result. + */ + public @NonNull NetworkStats addValues(@NonNull Entry entry) { + return this.clone().combineValues(entry); + } + + /** + * Add the given {@link NetworkStats} objects. + * + * @return the sum of two objects. + */ + public @NonNull NetworkStats add(@NonNull NetworkStats another) { + final NetworkStats ret = this.clone(); + ret.combineAllValues(another); + return ret; + } + + /** * Combine all values from another {@link NetworkStats} into this object. + * @hide */ - @UnsupportedAppUsage - public void combineAllValues(NetworkStats another) { + public void combineAllValues(@NonNull NetworkStats another) { NetworkStats.Entry entry = null; for (int i = 0; i < another.size; i++) { entry = another.getValues(i, entry); @@ -543,6 +657,7 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. + * @hide */ public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork) { @@ -560,6 +675,7 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters, starting * search around the hinted index as an optimization. + * @hide */ @VisibleForTesting public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, @@ -589,6 +705,7 @@ public class NetworkStats implements Parcelable { * Splice in {@link #operations} from the given {@link NetworkStats} based * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface}, * since operation counts are at data layer. + * @hide */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { @@ -604,6 +721,7 @@ public class NetworkStats implements Parcelable { /** * Return list of unique interfaces known by this data structure. + * @hide */ public String[] getUniqueIfaces() { final HashSet<String> ifaces = new HashSet<String>(); @@ -617,6 +735,7 @@ public class NetworkStats implements Parcelable { /** * Return list of unique UIDs known by this data structure. + * @hide */ @UnsupportedAppUsage public int[] getUniqueUids() { @@ -636,6 +755,7 @@ public class NetworkStats implements Parcelable { /** * Return total bytes represented by this snapshot object, usually used when * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. + * @hide */ @UnsupportedAppUsage public long getTotalBytes() { @@ -645,6 +765,7 @@ public class NetworkStats implements Parcelable { /** * Return total of all fields represented by this snapshot object. + * @hide */ @UnsupportedAppUsage public Entry getTotal(Entry recycle) { @@ -654,6 +775,7 @@ public class NetworkStats implements Parcelable { /** * Return total of all fields represented by this snapshot object matching * the requested {@link #uid}. + * @hide */ @UnsupportedAppUsage public Entry getTotal(Entry recycle, int limitUid) { @@ -663,11 +785,13 @@ public class NetworkStats implements Parcelable { /** * Return total of all fields represented by this snapshot object matching * the requested {@link #iface}. + * @hide */ public Entry getTotal(Entry recycle, HashSet<String> limitIface) { return getTotal(recycle, limitIface, UID_ALL, false); } + /** @hide */ @UnsupportedAppUsage public Entry getTotalIncludingTags(Entry recycle) { return getTotal(recycle, null, UID_ALL, true); @@ -717,6 +841,7 @@ public class NetworkStats implements Parcelable { /** * Fast path for battery stats. + * @hide */ public long getTotalPackets() { long total = 0; @@ -729,9 +854,12 @@ public class NetworkStats implements Parcelable { /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. + * time, and that none of them have disappeared. This method does not mutate + * the referencing object. + * + * @return the delta between two objects. */ - public NetworkStats subtract(NetworkStats right) { + public @NonNull NetworkStats subtract(@NonNull NetworkStats right) { return subtract(this, right, null, null); } @@ -742,6 +870,7 @@ public class NetworkStats implements Parcelable { * <p> * If counters have rolled backwards, they are clamped to {@code 0} and * reported to the given {@link NonMonotonicObserver}. + * @hide */ public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) { @@ -759,6 +888,7 @@ public class NetworkStats implements Parcelable { * If <var>recycle</var> is supplied, this NetworkStats object will be * reused (and returned) as the result if it is large enough to contain * the data. + * @hide */ public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) { @@ -817,7 +947,7 @@ public class NetworkStats implements Parcelable { entry.operations = Math.max(entry.operations, 0); } - result.addValues(entry); + result.addEntry(entry); } return result; @@ -847,6 +977,7 @@ public class NetworkStats implements Parcelable { * @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) { @@ -899,6 +1030,7 @@ public class NetworkStats implements Parcelable { * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as * base and stacked traffic. * @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); @@ -907,6 +1039,7 @@ public class NetworkStats implements Parcelable { /** * Return total statistics grouped by {@link #iface}; doesn't mutate the * original structure. + * @hide */ public NetworkStats groupedByIface() { final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); @@ -938,6 +1071,7 @@ public class NetworkStats implements Parcelable { /** * Return total statistics grouped by {@link #uid}; doesn't mutate the * original structure. + * @hide */ public NetworkStats groupedByUid() { final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); @@ -968,6 +1102,7 @@ public class NetworkStats implements Parcelable { /** * Remove all rows that match one of specified UIDs. + * @hide */ public void removeUids(int[] uids) { int nextOutputEntry = 0; @@ -989,6 +1124,7 @@ public class NetworkStats implements Parcelable { * @param limitUid UID to filter for, or {@link #UID_ALL}. * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}. * @param limitTag Tag to filter for, or {@link #TAG_ALL}. + * @hide */ public void filter(int limitUid, String[] limitIfaces, int limitTag) { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { @@ -1004,6 +1140,7 @@ public class NetworkStats implements Parcelable { * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. * * <p>This mutates the original structure in place. + * @hide */ public void filterDebugEntries() { filter(e -> e.set < SET_DEBUG_START); @@ -1024,6 +1161,7 @@ public class NetworkStats implements Parcelable { size = nextOutputEntry; } + /** @hide */ public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); @@ -1047,6 +1185,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #set} value. + * @hide */ public static String setToString(int set) { switch (set) { @@ -1067,6 +1206,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #set} value. + * @hide */ public static String setToCheckinString(int set) { switch (set) { @@ -1087,6 +1227,7 @@ public class NetworkStats implements Parcelable { /** * @return true if the querySet matches the dataSet. + * @hide */ public static boolean setMatches(int querySet, int dataSet) { if (querySet == dataSet) { @@ -1098,6 +1239,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #tag} value. + * @hide */ public static String tagToString(int tag) { return "0x" + Integer.toHexString(tag); @@ -1105,6 +1247,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #metered} value. + * @hide */ public static String meteredToString(int metered) { switch (metered) { @@ -1121,6 +1264,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #roaming} value. + * @hide */ public static String roamingToString(int roaming) { switch (roaming) { @@ -1137,6 +1281,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #defaultNetwork} value. + * @hide */ public static String defaultNetworkToString(int defaultNetwork) { switch (defaultNetwork) { @@ -1151,6 +1296,7 @@ public class NetworkStats implements Parcelable { } } + /** @hide */ @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); @@ -1163,8 +1309,7 @@ public class NetworkStats implements Parcelable { return 0; } - @UnsupportedAppUsage - public static final @android.annotation.NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() { + public static final @NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() { @Override public NetworkStats createFromParcel(Parcel in) { return new NetworkStats(in); @@ -1176,6 +1321,7 @@ public class NetworkStats implements Parcelable { } }; + /** @hide */ public interface NonMonotonicObserver<C> { public void foundNonMonotonic( NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie); @@ -1195,6 +1341,7 @@ public class NetworkStats implements Parcelable { * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel * @param underlyingIfaces underlying network ifaces used by the VPN application + * @hide */ public void migrateTun(int tunUid, @NonNull String tunIface, @NonNull String[] underlyingIfaces) { diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index f61260ee3ed0..7b799e262419 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -30,7 +30,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 87c7118c0ed8..5e6c47a47a8e 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,7 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.removeDoubleQuotes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index d0f54b4c7f2d..08cc4e24b245 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -20,7 +20,7 @@ import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.shared.Inet4AddressUtils; import android.os.Build; import android.system.ErrnoException; @@ -61,13 +61,6 @@ public class NetworkUtils { public static native void detachBPFFilter(FileDescriptor fd) throws SocketException; /** - * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. - * @param fd the socket's {@link FileDescriptor}. - * @param ifIndex the interface index. - */ - public native static void setupRaSocket(FileDescriptor fd, int ifIndex) throws SocketException; - - /** * Binds the current process to the network designated by {@code netId}. All sockets created * in the future (and not explicitly bound via a bound {@link SocketFactory} (see * {@link Network#getSocketFactory}) will be bound to this network. Note that if this diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS index a1c7fce67d30..767b69351065 100644 --- a/core/java/android/net/OWNERS +++ b/core/java/android/net/OWNERS @@ -8,4 +8,4 @@ lorenzo@google.com reminv@google.com satk@google.com -per-file SSL*, Uri*, Url* = flooey@google.com, narayan@google.com, tobiast@google.com +per-file SSL*, Uri*, Url* = prb@google.com, dauletz@google.com, narayan@google.com, tobiast@google.com diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 4600942806a8..4ba7394a4bb2 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -18,7 +18,7 @@ package android.net; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.text.TextUtils; import android.util.Log; diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 9d92db448668..ffe9ae9521a8 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -18,7 +18,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 52d3fc48a3a5..ea6002ca29e6 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 39cb323d0662..8b6ac4271c30 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.SystemProperties; import android.util.Log; diff --git a/core/java/android/net/SSLSessionCache.java b/core/java/android/net/SSLSessionCache.java index 9667e82c988c..944bc549acca 100644 --- a/core/java/android/net/SSLSessionCache.java +++ b/core/java/android/net/SSLSessionCache.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.Log; diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java index f9c2defc0377..8c6faf6d9970 100644 --- a/core/java/android/net/SntpClient.java +++ b/core/java/android/net/SntpClient.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.SystemClock; import android.util.Log; diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java index ec73866a647d..fc9a8f63c131 100644 --- a/core/java/android/net/SocketKeepalive.java +++ b/core/java/android/net/SocketKeepalive.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -53,7 +54,11 @@ import java.util.concurrent.Executor; public abstract class SocketKeepalive implements AutoCloseable { static final String TAG = "SocketKeepalive"; - /** @hide */ + /** + * No errors. + * @hide + */ + @SystemApi public static final int SUCCESS = 0; /** @hide */ @@ -147,17 +152,6 @@ public abstract class SocketKeepalive implements AutoCloseable { } } - /** - * This packet is invalid. - * See the error code for details. - * @hide - */ - public static class InvalidPacketException extends ErrorCodeException { - public InvalidPacketException(final int error) { - super(error); - } - } - @NonNull final IConnectivityManager mService; @NonNull final Network mNetwork; @NonNull final ParcelFileDescriptor mPfd; diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index 990c1142284c..f24a9bd53039 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.shared.InetAddressUtils; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/TelephonyNetworkSpecifier.java b/core/java/android/net/TelephonyNetworkSpecifier.java new file mode 100644 index 000000000000..726f77059707 --- /dev/null +++ b/core/java/android/net/TelephonyNetworkSpecifier.java @@ -0,0 +1,146 @@ +/* + * 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.net; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * NetworkSpecifier object for cellular network request. Apps should use the + * {@link TelephonyNetworkSpecifier.Builder} class to create an instance. + */ +public final class TelephonyNetworkSpecifier extends NetworkSpecifier implements Parcelable { + + private final int mSubId; + + /** + * Return the subscription Id of current TelephonyNetworkSpecifier object. + * + * @return The subscription id. + */ + public int getSubscriptionId() { + return mSubId; + } + + /** + * @hide + */ + public TelephonyNetworkSpecifier(int subId) { + this.mSubId = subId; + } + + public static final @NonNull Creator<TelephonyNetworkSpecifier> CREATOR = + new Creator<TelephonyNetworkSpecifier>() { + @Override + public TelephonyNetworkSpecifier createFromParcel(Parcel in) { + int subId = in.readInt(); + return new TelephonyNetworkSpecifier(subId); + } + + @Override + public TelephonyNetworkSpecifier[] newArray(int size) { + return new TelephonyNetworkSpecifier[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSubId); + } + + @Override + public int hashCode() { + return mSubId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof TelephonyNetworkSpecifier)) { + return false; + } + + TelephonyNetworkSpecifier lhs = (TelephonyNetworkSpecifier) obj; + return mSubId == lhs.mSubId; + } + + @Override + public String toString() { + return new StringBuilder() + .append("TelephonyNetworkSpecifier [") + .append("mSubId = ").append(mSubId) + .append("]") + .toString(); + } + + /** @hide */ + @Override + public boolean satisfiedBy(NetworkSpecifier other) { + // Any generic requests should be satisfied by a specific telephony network. + // For simplicity, we treat null same as MatchAllNetworkSpecifier + return equals(other) || other == null || other instanceof MatchAllNetworkSpecifier; + } + + + /** + * Builder to create {@link TelephonyNetworkSpecifier} object. + */ + public static final class Builder { + // Integer.MIN_VALUE which is not a valid subId, services as the sentinel to check if + // subId was set + private static final int SENTINEL_SUB_ID = Integer.MIN_VALUE; + + private int mSubId; + + public Builder() { + mSubId = SENTINEL_SUB_ID; + } + + /** + * Set the subscription id. + * + * @param subId The subscription Id. + * @return Instance of {@link Builder} to enable the chaining of the builder method. + */ + public @NonNull Builder setSubscriptionId(int subId) { + mSubId = subId; + return this; + } + + /** + * Create a NetworkSpecifier for the cellular network request. + * + * @return TelephonyNetworkSpecifier object. + * @throws IllegalArgumentException when subscription Id is not provided through + * {@link #setSubscriptionId(int)}. + */ + public @NonNull TelephonyNetworkSpecifier build() { + if (mSubId == SENTINEL_SUB_ID) { + throw new IllegalArgumentException("Subscription Id is not provided."); + } + return new TelephonyNetworkSpecifier(mSubId); + } + } +} diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index bf4884aa96a7..8108cf08d5c3 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -20,10 +20,10 @@ import android.annotation.NonNull; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.DownloadManager; import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.MediaPlayer; import android.os.Build; @@ -89,7 +89,7 @@ public class TrafficStats { * * @hide */ - public static final int UID_TETHERING = -5; + public static final int UID_TETHERING = NetworkStats.UID_TETHERING; /** * Tag values in this range are reserved for the network stack. The network stack is diff --git a/core/java/android/net/Uri.aidl b/core/java/android/net/Uri.aidl index 6bd3be5e041b..b85f63bbcdd2 100644 --- a/core/java/android/net/Uri.aidl +++ b/core/java/android/net/Uri.aidl @@ -16,4 +16,4 @@ package android.net; -parcelable Uri; +@JavaOnlyStableParcelable parcelable Uri; diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index c3166e91fac7..ddca4b464123 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -19,7 +19,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Environment; import android.os.Parcel; diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index ed7cddcc6036..4b804b097d59 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -23,11 +23,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.PendingIntent; import android.app.Service; import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java index 994c794e6997..aa3777d55342 100644 --- a/core/java/android/net/WebAddress.java +++ b/core/java/android/net/WebAddress.java @@ -20,7 +20,7 @@ import static android.util.Patterns.GOOD_IRI_CHAR; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import java.util.Locale; diff --git a/core/java/android/net/annotations/PolicyDirection.java b/core/java/android/net/annotations/PolicyDirection.java new file mode 100644 index 000000000000..febd9b406111 --- /dev/null +++ b/core/java/android/net/annotations/PolicyDirection.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.annotations; + +import android.annotation.IntDef; +import android.net.IpSecManager; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * IPsec traffic direction. + * + * <p>Mainline modules cannot reference hidden @IntDef. Moving this annotation to a separate class + * to allow others to statically include it. + * + * @hide + */ +@IntDef(value = {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}) +@Retention(RetentionPolicy.SOURCE) +public @interface PolicyDirection {} diff --git a/core/java/android/net/http/OWNERS b/core/java/android/net/http/OWNERS index 6b8c9edf4257..309261277024 100644 --- a/core/java/android/net/http/OWNERS +++ b/core/java/android/net/http/OWNERS @@ -1,3 +1,4 @@ -flooey@google.com narayan@google.com tobiast@google.com +include platform/libcore:/OWNERS +include platform/external/conscrypt:/OWNERS diff --git a/core/java/android/net/http/SslCertificate.java b/core/java/android/net/http/SslCertificate.java index 01dd08f4ad9c..250cff29944a 100644 --- a/core/java/android/net/http/SslCertificate.java +++ b/core/java/android/net/http/SslCertificate.java @@ -17,7 +17,7 @@ package android.net.http; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Bundle; import android.text.format.DateFormat; diff --git a/core/java/android/net/http/SslError.java b/core/java/android/net/http/SslError.java index b3f2fb79b5c3..d43c616a4f13 100644 --- a/core/java/android/net/http/SslError.java +++ b/core/java/android/net/http/SslError.java @@ -16,8 +16,9 @@ package android.net.http; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; + import java.security.cert.X509Certificate; /** diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java index 8243be9c1355..f93907a37f3f 100644 --- a/core/java/android/net/metrics/ApfProgramEvent.java +++ b/core/java/android/net/metrics/ApfProgramEvent.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java index eac5579f9eaa..b221cb97b28f 100644 --- a/core/java/android/net/metrics/ApfStats.java +++ b/core/java/android/net/metrics/ApfStats.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java index 5f9f50708a49..8fc1ef80bba9 100644 --- a/core/java/android/net/metrics/DhcpClientEvent.java +++ b/core/java/android/net/metrics/DhcpClientEvent.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java b/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java new file mode 100644 index 000000000000..740aa92ad484 --- /dev/null +++ b/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java @@ -0,0 +1,70 @@ +/* + * 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.net.netstats.provider; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.net.NetworkStats; + +/** + * A base class that allows external modules to implement a custom network statistics provider. + * @hide + */ +@SystemApi +public abstract class AbstractNetworkStatsProvider { + /** + * A value used by {@link #setLimit} and {@link #setAlert} indicates there is no limit. + */ + public static final int QUOTA_UNLIMITED = -1; + + /** + * Called by {@code NetworkStatsService} when global polling is needed. Custom + * implementation of providers MUST respond to it by calling + * {@link NetworkStatsProviderCallback#onStatsUpdated} within one minute. Responding + * later than this may cause the stats to be dropped. + * + * @param token a positive number identifying the new state of the system under which + * {@link NetworkStats} have to be gathered from now on. When this is called, + * custom implementations of providers MUST report the latest stats with the + * previous token, under which stats were being gathered so far. + */ + public abstract void requestStatsUpdate(int token); + + /** + * Called by {@code NetworkStatsService} when setting the interface quota for the specified + * upstream interface. When this is called, the custom implementation should block all egress + * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have + * been reached, and MUST respond to it by calling + * {@link NetworkStatsProviderCallback#onLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + */ + public abstract void setLimit(@NonNull String iface, long quotaBytes); + + /** + * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations + * MUST call {@link NetworkStatsProviderCallback#onAlertReached()} when {@code quotaBytes} bytes + * have been reached. Unlike {@link #setLimit(String, long)}, the custom implementation should + * not block all egress packets. + * + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. + */ + public abstract void setAlert(long quotaBytes); +} diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl new file mode 100644 index 000000000000..55b3d4edb157 --- /dev/null +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -0,0 +1,28 @@ +/* + * 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.net.netstats.provider; + +/** + * Interface for NetworkStatsService to query network statistics and set data limits. + * + * @hide + */ +oneway interface INetworkStatsProvider { + void requestStatsUpdate(int token); + void setLimit(String iface, long quotaBytes); + void setAlert(long quotaBytes); +} diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl new file mode 100644 index 000000000000..3ea9318f10d4 --- /dev/null +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -0,0 +1,31 @@ +/* + * 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.net.netstats.provider; + +import android.net.NetworkStats; + +/** + * Interface for implementor of {@link INetworkStatsProviderCallback} to push events + * such as network statistics update or notify limit reached. + * @hide + */ +oneway interface INetworkStatsProviderCallback { + void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); + void onAlertReached(); + void onLimitReached(); + void unregister(); +} diff --git a/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java b/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java new file mode 100644 index 000000000000..e17a8eee7ff0 --- /dev/null +++ b/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java @@ -0,0 +1,98 @@ +/* + * 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.net.netstats.provider; + +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.net.NetworkStats; +import android.os.RemoteException; + +/** + * A callback class that allows callers to report events to the system. + * @hide + */ +@SystemApi +@SuppressLint("CallbackMethodName") +public class NetworkStatsProviderCallback { + @NonNull private final INetworkStatsProviderCallback mBinder; + + /** @hide */ + public NetworkStatsProviderCallback(@NonNull INetworkStatsProviderCallback binder) { + mBinder = binder; + } + + /** + * Notify the system of new network statistics. + * + * Send the network statistics recorded since the last call to {@link #onStatsUpdated}. Must be + * called within one minute of {@link AbstractNetworkStatsProvider#requestStatsUpdate(int)} + * being called. The provider can also call this whenever it wants to reports new stats for any + * reason. Note that the system will not necessarily immediately propagate the statistics to + * reflect the update. + * + * @param token the token under which these stats were gathered. Providers can call this method + * with the current token as often as they want, until the token changes. + * {@see AbstractNetworkStatsProvider#requestStatsUpdate()} + * @param ifaceStats the {@link NetworkStats} per interface to be reported. + * The provider should not include any traffic that is already counted by + * kernel interface counters. + * @param uidStats the same stats as above, but counts {@link NetworkStats} + * per uid. + */ + public void onStatsUpdated(int token, @NonNull NetworkStats ifaceStats, + @NonNull NetworkStats uidStats) { + try { + mBinder.onStatsUpdated(token, ifaceStats, uidStats); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code setAlert} has been reached. + */ + public void onAlertReached() { + try { + mBinder.onAlertReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code setLimit} has been reached. + */ + public void onLimitReached() { + try { + mBinder.onLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Unregister the provider and the referencing callback. + */ + public void unregister() { + try { + mBinder.unregister(); + } catch (RemoteException e) { + // Ignore error. + } + } +} diff --git a/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java b/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java new file mode 100644 index 000000000000..4bf7c9bc086e --- /dev/null +++ b/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java @@ -0,0 +1,48 @@ +/* + * 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.net.netstats.provider; + +import android.annotation.NonNull; + +/** + * A wrapper class of {@link INetworkStatsProvider} that hides the binder interface from exposing + * to outer world. + * + * @hide + */ +public class NetworkStatsProviderWrapper extends INetworkStatsProvider.Stub { + @NonNull final AbstractNetworkStatsProvider mProvider; + + public NetworkStatsProviderWrapper(AbstractNetworkStatsProvider provider) { + mProvider = provider; + } + + @Override + public void requestStatsUpdate(int token) { + mProvider.requestStatsUpdate(token); + } + + @Override + public void setLimit(@NonNull String iface, long quotaBytes) { + mProvider.setLimit(iface, quotaBytes); + } + + @Override + public void setAlert(long quotaBytes) { + mProvider.setAlert(quotaBytes); + } +} diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 459b1409807b..0946499f164f 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -17,13 +17,13 @@ package android.net.nsd; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; -import android.os.Parcelable; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; +import android.os.Parcelable; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Base64; import android.util.Log; -import android.util.ArrayMap; import java.io.UnsupportedEncodingException; import java.net.InetAddress; diff --git a/core/java/android/nfc/ErrorCodes.java b/core/java/android/nfc/ErrorCodes.java index 98e31ad53be3..d2c81cd27d90 100644 --- a/core/java/android/nfc/ErrorCodes.java +++ b/core/java/android/nfc/ErrorCodes.java @@ -16,7 +16,7 @@ package android.nfc; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * This class defines all the error codes that can be returned by the service diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java index 5044a860b50c..fe316c45fb55 100644 --- a/core/java/android/nfc/NdefRecord.java +++ b/core/java/android/nfc/NdefRecord.java @@ -16,7 +16,7 @@ package android.nfc; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.net.Uri; import android.os.Parcel; diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java index abfa133a2f39..935374d15d9b 100644 --- a/core/java/android/nfc/NfcActivityManager.java +++ b/core/java/android/nfc/NfcActivityManager.java @@ -16,9 +16,9 @@ package android.nfc; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.Application; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProvider; import android.content.Intent; import android.net.Uri; @@ -26,7 +26,6 @@ import android.nfc.NfcAdapter.ReaderCallback; import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; -import android.os.UserHandle; import android.util.Log; import java.util.ArrayList; diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 7ab984fc9275..d320f61a3657 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -21,11 +21,11 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.ActivityThread; import android.app.OnActivityPausedListener; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.IntentFilter; import android.content.pm.IPackageManager; diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java index 030066eb80a4..644e3122774b 100644 --- a/core/java/android/nfc/NfcManager.java +++ b/core/java/android/nfc/NfcManager.java @@ -17,7 +17,7 @@ package android.nfc; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java index 5a4c465f76d8..b9e6ff4a5a9e 100644 --- a/core/java/android/nfc/Tag.java +++ b/core/java/android/nfc/Tag.java @@ -16,7 +16,7 @@ package android.nfc; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.nfc.tech.IsoDep; import android.nfc.tech.MifareClassic; @@ -455,12 +455,12 @@ public final class Tag implements Parcelable { * * @hide */ - public synchronized void setConnectedTechnology(int technology) { - if (mConnectedTechnology == -1) { - mConnectedTechnology = technology; - } else { - throw new IllegalStateException("Close other technology first!"); + public synchronized boolean setConnectedTechnology(int technology) { + if (mConnectedTechnology != -1) { + return false; } + mConnectedTechnology = technology; + return true; } /** diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java index 77b5552cd27b..c4f5e0b2ddf2 100644 --- a/core/java/android/nfc/cardemulation/AidGroup.java +++ b/core/java/android/nfc/cardemulation/AidGroup.java @@ -16,18 +16,18 @@ package android.nfc.cardemulation; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; -import android.annotation.UnsupportedAppUsage; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; /** * The AidGroup class represents a group of Application Identifiers (AIDs). diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java index d9000e43be0b..8da9db17252f 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -16,7 +16,7 @@ package android.nfc.cardemulation; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/core/java/android/nfc/tech/BasicTagTechnology.java index b6b347ca0619..ae468fead7a2 100644 --- a/core/java/android/nfc/tech/BasicTagTechnology.java +++ b/core/java/android/nfc/tech/BasicTagTechnology.java @@ -75,7 +75,10 @@ abstract class BasicTagTechnology implements TagTechnology { if (errorCode == ErrorCodes.SUCCESS) { // Store this in the tag object - mTag.setConnectedTechnology(mSelectedTechnology); + if (!mTag.setConnectedTechnology(mSelectedTechnology)) { + Log.e(TAG, "Close other technology first!"); + throw new IOException("Only one TagTechnology can be connected at a time."); + } mIsConnected = true; } else if (errorCode == ErrorCodes.ERROR_NOT_SUPPORTED) { throw new UnsupportedOperationException("Connecting to " + diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java index 6daa5b4dc6d8..92574968e965 100644 --- a/core/java/android/os/AppZygote.java +++ b/core/java/android/os/AppZygote.java @@ -21,6 +21,8 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; +import dalvik.system.VMRuntime; + /** * AppZygote is responsible for interfacing with an application-specific zygote. * @@ -113,7 +115,7 @@ public class AppZygote { "app_zygote", // seInfo abi, // abi abi, // acceptedAbiList - null, // instructionSet + VMRuntime.getInstructionSet(abi), // instructionSet mZygoteUidGidMin, mZygoteUidGidMax); diff --git a/core/java/android/os/AsyncResult.java b/core/java/android/os/AsyncResult.java index 58a27015f2df..e80528b10aaf 100644 --- a/core/java/android/os/AsyncResult.java +++ b/core/java/android/os/AsyncResult.java @@ -16,8 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; -import android.os.Message; +import android.compat.annotation.UnsupportedAppUsage; /** @hide */ public class AsyncResult diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java index b37e176ddb6e..e1dabd345027 100644 --- a/core/java/android/os/AsyncTask.java +++ b/core/java/android/os/AsyncTask.java @@ -18,8 +18,8 @@ package android.os; import android.annotation.MainThread; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; +import android.compat.annotation.UnsupportedAppUsage; import java.util.ArrayDeque; import java.util.concurrent.Callable; diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 7f63f8fb9e28..e6ad917fa019 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -18,7 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; import android.util.Log; import android.util.MathUtils; diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 5ced86c9e79a..12ec0a0c21d5 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -21,7 +21,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.hardware.health.V1_0.Constants; diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 6efe1de4ac45..44f7fa35727c 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -19,9 +19,9 @@ package android.os; import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.job.JobParameters; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.server.ServerProtoEnums; diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 2e6d2cc4a66a..9c4a36f1c965 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -19,7 +19,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.ExceptionUtils; import android.util.Log; import android.util.Slog; diff --git a/core/java/android/os/Broadcaster.java b/core/java/android/os/Broadcaster.java index 6ac7f1a9c970..d1a953f23f7f 100644 --- a/core/java/android/os/Broadcaster.java +++ b/core/java/android/os/Broadcaster.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** @hide */ public class Broadcaster diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 1d25bc1db6bc..6750fc77e705 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -22,9 +22,9 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.Application; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.sysprop.TelephonyProperties; import android.text.TextUtils; @@ -161,7 +161,7 @@ public class Build { try { Application application = ActivityThread.currentApplication(); String callingPackage = application != null ? application.getPackageName() : null; - return service.getSerialForPackage(callingPackage); + return service.getSerialForPackage(callingPackage, null); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index b82e517c08ae..a2071e0b0dc8 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -17,7 +17,7 @@ package android.os; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; import android.util.Size; import android.util.SizeF; diff --git a/core/java/android/os/CancellationSignal.java b/core/java/android/os/CancellationSignal.java index 99fb9982e706..260f7ade8ab7 100644 --- a/core/java/android/os/CancellationSignal.java +++ b/core/java/android/os/CancellationSignal.java @@ -16,9 +16,7 @@ package android.os; -import android.os.ICancellationSignal; - -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Provides the ability to cancel an operation in progress. diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index d7ed05577697..50379222f1a9 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -18,8 +18,8 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.AppGlobals; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.Log; diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java index b7cccc66294a..18ba5a8a4a34 100644 --- a/core/java/android/os/DropBoxManager.java +++ b/core/java/android/os/DropBoxManager.java @@ -24,7 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.Log; diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 7a131e5680a8..6639d57a189c 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -20,10 +20,10 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java index 4d9ebc2b5923..4628910bfd52 100644 --- a/core/java/android/os/FileObserver.java +++ b/core/java/android/os/FileObserver.java @@ -19,7 +19,7 @@ package android.os; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; import java.io.File; diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 2ac3def3a3f9..a47fbbaab9dd 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -40,7 +40,7 @@ import static android.system.OsConstants.W_OK; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.provider.DocumentsContract.Document; import android.system.ErrnoException; diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index a99bdabee137..fa7404c5b139 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -18,7 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; import android.util.Printer; diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java index 09afdc7f934e..7c42c36e7747 100644 --- a/core/java/android/os/HwBinder.java +++ b/core/java/android/os/HwBinder.java @@ -18,7 +18,7 @@ package android.os; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import libcore.util.NativeAllocationRegistry; diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java index 9786f16bebaa..fb36e6f6978f 100644 --- a/core/java/android/os/HwParcel.java +++ b/core/java/android/os/HwParcel.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import dalvik.annotation.optimization.FastNative; diff --git a/core/java/android/os/HwRemoteBinder.java b/core/java/android/os/HwRemoteBinder.java index 72ec958ca6d6..756202e88518 100644 --- a/core/java/android/os/HwRemoteBinder.java +++ b/core/java/android/os/HwRemoteBinder.java @@ -16,7 +16,8 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import libcore.util.NativeAllocationRegistry; /** @hide */ diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index 83f88ad41cfc..d9ed32799ea5 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -18,7 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.FileDescriptor; diff --git a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl index 87d358f50e74..d11aa0c0bac6 100644 --- a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl +++ b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl @@ -21,5 +21,5 @@ package android.os; */ interface IDeviceIdentifiersPolicyService { String getSerial(); - String getSerialForPackage(in String callingPackage); -}
\ No newline at end of file + String getSerialForPackage(in String callingPackage, String callingFeatureId); +} diff --git a/core/java/android/os/IVibratorService.aidl b/core/java/android/os/IVibratorService.aidl index 6b881fecad56..264ab6038ea6 100644 --- a/core/java/android/os/IVibratorService.aidl +++ b/core/java/android/os/IVibratorService.aidl @@ -24,7 +24,8 @@ interface IVibratorService { boolean hasVibrator(); boolean hasAmplitudeControl(); - boolean setAlwaysOnEffect(int id, in VibrationEffect effect, in AudioAttributes attributes); + boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, in VibrationEffect effect, + in AudioAttributes attributes); void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes, String reason, IBinder token); void cancelVibrate(IBinder token); diff --git a/core/java/android/os/LocaleList.java b/core/java/android/os/LocaleList.java index 0de09efad8ea..0bf387e6d0a6 100644 --- a/core/java/android/os/LocaleList.java +++ b/core/java/android/os/LocaleList.java @@ -20,7 +20,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.icu.util.ULocale; import com.android.internal.annotations.GuardedBy; diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index d468972df413..5dc64d5b8d51 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -18,7 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; import android.util.Printer; import android.util.Slog; diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java index 5a1e3d429830..f84f9f05b13e 100644 --- a/core/java/android/os/MemoryFile.java +++ b/core/java/android/os/MemoryFile.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.system.ErrnoException; import java.io.FileDescriptor; diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java index 6055befa15d5..8ac245b894bb 100644 --- a/core/java/android/os/Message.java +++ b/core/java/android/os/Message.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index f98fdc393de3..4e910577dd49 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -19,8 +19,7 @@ package android.os; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; -import android.os.MessageQueueProto; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; import android.util.Printer; import android.util.SparseArray; diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 041f31d67a3e..382c838447b2 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -19,7 +19,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 2a4576adf192..214b3bb91af6 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -32,7 +32,7 @@ import static android.system.OsConstants.S_ISREG; import static android.system.OsConstants.S_IWOTH; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ContentProvider; import android.os.MessageQueue.OnFileDescriptorEventListener; diff --git a/core/java/android/os/ParcelUuid.java b/core/java/android/os/ParcelUuid.java index cc50c8996ba7..0b52c7501d5b 100644 --- a/core/java/android/os/ParcelUuid.java +++ b/core/java/android/os/ParcelUuid.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.UUID; diff --git a/core/java/android/os/ParcelableParcel.java b/core/java/android/os/ParcelableParcel.java index 61f39686c9e6..38d980ecb0f1 100644 --- a/core/java/android/os/ParcelableParcel.java +++ b/core/java/android/os/ParcelableParcel.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.MathUtils; /** diff --git a/core/java/android/os/PerformanceCollector.java b/core/java/android/os/PerformanceCollector.java index 33c86b8b05b9..27de48d40188 100644 --- a/core/java/android/os/PerformanceCollector.java +++ b/core/java/android/os/PerformanceCollector.java @@ -17,7 +17,8 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; /** diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java index 6f1bf71f187b..29aaf534eda1 100644 --- a/core/java/android/os/PersistableBundle.java +++ b/core/java/android/os/PersistableBundle.java @@ -16,17 +16,24 @@ package android.os; +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; /** @@ -339,4 +346,44 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa proto.end(token); } + + /** + * Writes the content of the {@link PersistableBundle} to a {@link OutputStream}. + * + * <p>The content can be read by a {@link #readFromStream}. + * + * @see #readFromStream + */ + public void writeToStream(@NonNull OutputStream outputStream) throws IOException { + FastXmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(outputStream, UTF_8.name()); + serializer.startTag(null, "bundle"); + try { + saveToXml(serializer); + } catch (XmlPullParserException e) { + throw new IOException(e); + } + serializer.endTag(null, "bundle"); + serializer.flush(); + } + + /** + * Reads a {@link PersistableBundle} from an {@link InputStream}. + * + * <p>The stream must be generated by {@link #writeToStream}. + * + * @see #writeToStream + */ + @NonNull + public static PersistableBundle readFromStream(@NonNull InputStream inputStream) + throws IOException { + try { + XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); + parser.setInput(inputStream, UTF_8.name()); + parser.next(); + return PersistableBundle.restoreFromXml(parser); + } catch (XmlPullParserException e) { + throw new IOException(e); + } + } } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index c618dbc2b551..febc36cbe47b 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -26,7 +26,7 @@ import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.service.dreams.Sandman; import android.util.ArrayMap; diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 1130f1db6256..6f4f30c4981a 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -19,7 +19,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.system.Os; import android.system.OsConstants; import android.webkit.WebViewZygote; @@ -740,11 +740,12 @@ public class Process { /** * Set the priority of a thread, based on Linux priorities. - * - * @param tid The identifier of the thread/process to change. + * + * @param tid The identifier of the thread/process to change. It should be + * the native thread id but not the managed id of {@link java.lang.Thread}. * @param priority A Linux priority level, from -20 for highest scheduling * priority to 19 for lowest scheduling priority. - * + * * @throws IllegalArgumentException Throws IllegalArgumentException if * <var>tid</var> does not exist. * @throws SecurityException Throws SecurityException if your process does diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index e3f6e120d9c6..190182072356 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -22,8 +22,8 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; diff --git a/core/java/android/os/Registrant.java b/core/java/android/os/Registrant.java index 572b975fbafd..d6afd049f156 100644 --- a/core/java/android/os/Registrant.java +++ b/core/java/android/os/Registrant.java @@ -16,9 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; -import android.os.Handler; -import android.os.Message; +import android.compat.annotation.UnsupportedAppUsage; import java.lang.ref.WeakReference; diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java index 9c017dfff967..98f949bbfd84 100644 --- a/core/java/android/os/RegistrantList.java +++ b/core/java/android/os/RegistrantList.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.ArrayList; diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java index da58d0fac160..373060f4ff4b 100644 --- a/core/java/android/os/RemoteCallback.java +++ b/core/java/android/os/RemoteCallback.java @@ -20,8 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; - -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index 6165146ece0a..df4ade09753b 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; import android.util.Slog; diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java index 2e673a857a93..c2f7f1bf2099 100644 --- a/core/java/android/os/RemoteException.java +++ b/core/java/android/os/RemoteException.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.AndroidException; /** diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java index 34809e76c91b..f64a81177ce2 100644 --- a/core/java/android/os/SELinux.java +++ b/core/java/android/os/SELinux.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Slog; import java.io.File; diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java index bf9225a2780a..c008f4d37b90 100644 --- a/core/java/android/os/ServiceManager.java +++ b/core/java/android/os/ServiceManager.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; import android.util.Log; diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java index 94671c8f317d..39ddcb2af3c2 100644 --- a/core/java/android/os/ServiceManagerNative.java +++ b/core/java/android/os/ServiceManagerNative.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Native implementation of the service manager. Most clients will only diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java index 57a88012a31a..26d9c7d687eb 100644 --- a/core/java/android/os/SharedMemory.java +++ b/core/java/android/os/SharedMemory.java @@ -18,7 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java index 2fe8726a0915..814aac4116e1 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Slog; import com.android.internal.util.FastPrintWriter; diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java index 881d0b4d9c8e..6d1a1164abb4 100644 --- a/core/java/android/os/StatFs.java +++ b/core/java/android/os/StatFs.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.system.ErrnoException; import android.system.Os; import android.system.StructStatVfs; diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 0bf634e799cd..3faaff73a0ea 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -20,10 +20,10 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.IActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java index 210f5d7b5dab..29852a872f5d 100644 --- a/core/java/android/os/SystemClock.java +++ b/core/java/android/os/SystemClock.java @@ -17,8 +17,8 @@ package android.os; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.IAlarmManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.location.ILocationManager; import android.location.LocationTime; diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java index f08e1ff16999..a681ec06c19f 100644 --- a/core/java/android/os/SystemProperties.java +++ b/core/java/android/os/SystemProperties.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; import android.util.MutableInt; diff --git a/core/java/android/os/SystemService.java b/core/java/android/os/SystemService.java index 968c761c5ff0..5871d2d9b58f 100644 --- a/core/java/android/os/SystemService.java +++ b/core/java/android/os/SystemService.java @@ -16,9 +16,10 @@ package android.os; +import android.compat.annotation.UnsupportedAppUsage; + import com.google.android.collect.Maps; -import android.annotation.UnsupportedAppUsage; import java.util.HashMap; import java.util.concurrent.TimeoutException; diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java index fbd11ca62a0c..11a425d54621 100644 --- a/core/java/android/os/SystemVibrator.java +++ b/core/java/android/os/SystemVibrator.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.AudioAttributes; import android.util.Log; @@ -70,13 +70,14 @@ public class SystemVibrator extends Vibrator { } @Override - public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attributes) { + public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, + AudioAttributes attributes) { if (mService == null) { Log.w(TAG, "Failed to set always-on effect; no vibrator service."); return false; } try { - return mService.setAlwaysOnEffect(id, effect, attributes); + return mService.setAlwaysOnEffect(uid, opPkg, alwaysOnId, effect, attributes); } catch (RemoteException e) { Log.w(TAG, "Failed to set always-on effect.", e); } diff --git a/core/java/android/util/TimestampedValue.java b/core/java/android/os/TimestampedValue.java index 45056730b08b..f4c87ac9dfc9 100644 --- a/core/java/android/util/TimestampedValue.java +++ b/core/java/android/os/TimestampedValue.java @@ -14,13 +14,11 @@ * limitations under the License. */ -package android.util; +package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.SystemClock; +import android.annotation.SystemApi; import java.util.Objects; @@ -38,19 +36,27 @@ import java.util.Objects; * @param <T> the type of the value with an associated timestamp * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class TimestampedValue<T> implements Parcelable { private final long mReferenceTimeMillis; + @Nullable private final T mValue; - public TimestampedValue(long referenceTimeMillis, T value) { + public TimestampedValue(long referenceTimeMillis, @Nullable T value) { mReferenceTimeMillis = referenceTimeMillis; mValue = value; } + /** Returns the reference time value. See {@link TimestampedValue} for more information. */ public long getReferenceTimeMillis() { return mReferenceTimeMillis; } + /** + * Returns the value associated with the timestamp. See {@link TimestampedValue} for more + * information. + */ + @Nullable public T getValue() { return mValue; } @@ -89,6 +95,8 @@ public final class TimestampedValue<T> implements Parcelable { return one.mReferenceTimeMillis - two.mReferenceTimeMillis; } + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Parcelable.Creator<TimestampedValue<?>> CREATOR = new Parcelable.ClassLoaderCreator<TimestampedValue<?>>() { diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index e132c11d6c8e..25584f156084 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -17,9 +17,7 @@ package android.os; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; - -import com.android.internal.os.Zygote; +import android.compat.annotation.UnsupportedAppUsage; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java index dc98c4267a37..fa30e509f8cc 100644 --- a/core/java/android/os/UEventObserver.java +++ b/core/java/android/os/UEventObserver.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; import java.util.ArrayList; diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index a9ddffe7d55c..73e1adf134f2 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -16,8 +16,10 @@ package android.os; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.content.res.AssetFileDescriptor; import android.os.IUpdateEngine; import android.os.IUpdateEngineCallback; import android.os.RemoteException; @@ -140,8 +142,43 @@ public class UpdateEngine { * {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}. */ public static final int UPDATED_BUT_NOT_ACTIVE = 52; + + /** + * Error code: there is not enough space on the device to apply the update. User should + * be prompted to free up space and re-try the update. + * + * <p>See {@link UpdateEngine#allocateSpace}. + */ + public static final int NOT_ENOUGH_SPACE = 60; + + /** + * Error code: the device is corrupted and no further updates may be applied. + * + * <p>See {@link UpdateEngine#cleanupAppliedPayload}. + */ + public static final int DEVICE_CORRUPTED = 61; } + /** @hide */ + @IntDef(value = { + ErrorCodeConstants.SUCCESS, + ErrorCodeConstants.ERROR, + ErrorCodeConstants.FILESYSTEM_COPIER_ERROR, + ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR, + ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR, + ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR, + ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR, + ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR, + ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR, + ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR, + ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR, + ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR, + ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE, + ErrorCodeConstants.NOT_ENOUGH_SPACE, + ErrorCodeConstants.DEVICE_CORRUPTED, + }) + public @interface ErrorCode {} + /** * Status codes for update engine. Values must agree with the ones in * {@code system/update_engine/client_library/include/update_engine/update_status.h}. @@ -313,16 +350,17 @@ public class UpdateEngine { } /** - * Applies the payload passed as ParcelFileDescriptor {@code pfd} instead of - * using the {@code file://} scheme. + * Applies the payload passed as AssetFileDescriptor {@code assetFd} + * instead of using the {@code file://} scheme. * * <p>See {@link #applyPayload(String)} for {@code offset}, {@code size} and * {@code headerKeyValuePairs} parameters. */ - public void applyPayload(@NonNull ParcelFileDescriptor pfd, long offset, long size, + public void applyPayload(@NonNull AssetFileDescriptor assetFd, @NonNull String[] headerKeyValuePairs) { try { - mUpdateEngine.applyPayloadFd(pfd, offset, size, headerKeyValuePairs); + mUpdateEngine.applyPayloadFd(assetFd.getParcelFileDescriptor(), + assetFd.getStartOffset(), assetFd.getLength(), headerKeyValuePairs); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -419,4 +457,138 @@ public class UpdateEngine { throw e.rethrowFromSystemServer(); } } + + /** + * Return value of {@link #allocateSpace.} + */ + public static final class AllocateSpaceResult { + private @ErrorCode int mErrorCode = ErrorCodeConstants.SUCCESS; + private long mFreeSpaceRequired = 0; + private AllocateSpaceResult() {} + /** + * Error code. + * + * @return The following error codes: + * <ul> + * <li>{@link ErrorCodeConstants#SUCCESS} if space has been allocated + * successfully.</li> + * <li>{@link ErrorCodeConstants#NOT_ENOUGH_SPACE} if insufficient + * space.</li> + * <li>Other {@link ErrorCodeConstants} for other errors.</li> + * </ul> + */ + @ErrorCode + public int errorCode() { + return mErrorCode; + } + + /** + * Estimated total space that needs to be available on the userdata partition to apply the + * payload (in bytes). + * + * <p> + * Note that in practice, more space needs to be made available before applying the payload + * to keep the device working. + * + * @return The following values: + * <ul> + * <li>zero if {@link #errorCode} returns {@link ErrorCodeConstants#SUCCESS}</li> + * <li>non-zero if {@link #errorCode} returns {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}. + * Value is the estimated total space required on userdata partition.</li> + * </ul> + * @throws IllegalStateException if {@link #errorCode} is not one of the above. + * + */ + public long freeSpaceRequired() { + if (mErrorCode == ErrorCodeConstants.SUCCESS) { + return 0; + } + if (mErrorCode == ErrorCodeConstants.NOT_ENOUGH_SPACE) { + return mFreeSpaceRequired; + } + throw new IllegalStateException(String.format( + "freeSpaceRequired() is not available when error code is %d", mErrorCode)); + } + } + + /** + * Initialize partitions for a payload associated with the given payload + * metadata {@code payloadMetadataFilename} by preallocating required space. + * + * <p>This function should be called after payload has been verified after + * {@link #verifyPayloadMetadata}. This function does not verify whether + * the given payload is applicable or not. + * + * <p>Implementation of {@code allocateSpace} uses + * {@code headerKeyValuePairs} to determine whether space has been allocated + * for a different or same payload previously. If space has been allocated + * for a different payload before, space will be reallocated for the given + * payload. If space has been allocated for the same payload, no actions to + * storage devices are taken. + * + * <p>This function is synchronous and may take a non-trivial amount of + * time. Callers should call this function in a background thread. + * + * @param payloadMetadataFilename See {@link #verifyPayloadMetadata}. + * @param headerKeyValuePairs See {@link #applyPayload}. + * @return See {@link AllocateSpaceResult}. + */ + @NonNull + public AllocateSpaceResult allocateSpace( + @NonNull String payloadMetadataFilename, + @NonNull String[] headerKeyValuePairs) { + AllocateSpaceResult result = new AllocateSpaceResult(); + try { + result.mFreeSpaceRequired = mUpdateEngine.allocateSpaceForPayload( + payloadMetadataFilename, + headerKeyValuePairs); + result.mErrorCode = result.mFreeSpaceRequired == 0 + ? ErrorCodeConstants.SUCCESS + : ErrorCodeConstants.NOT_ENOUGH_SPACE; + return result; + } catch (ServiceSpecificException e) { + result.mErrorCode = e.errorCode; + result.mFreeSpaceRequired = 0; + return result; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Cleanup files used by the previous update and free up space after the + * device has been booted successfully into the new build. + * + * <p>In particular, this function waits until delta files for snapshots for + * Virtual A/B update are merged to OS partitions, then delete these delta + * files. + * + * <p>This function is synchronous and may take a non-trivial amount of + * time. Callers should call this function in a background thread. + * + * <p>This function does not delete payload binaries downloaded for a + * non-streaming OTA update. + * + * @return One of the following: + * <ul> + * <li>{@link ErrorCodeConstants#SUCCESS} if execution is successful.</li> + * <li>{@link ErrorCodeConstants#ERROR} if a transient error has occurred. + * The device should be able to recover after a reboot. The function should + * be retried after the reboot.</li> + * <li>{@link ErrorCodeConstants#DEVICE_CORRUPTED} if a permanent error is + * encountered. Device is corrupted, and future updates must not be applied. + * The device cannot recover without flashing and factory resets. + * </ul> + * + * @throws ServiceSpecificException if other transient errors has occurred. + * A reboot may or may not help resolving the issue. + */ + @ErrorCode + public int cleanupAppliedPayload() { + try { + return mUpdateEngine.cleanupSuccessfulUpdate(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/os/UpdateEngineCallback.java b/core/java/android/os/UpdateEngineCallback.java index f07294e222e2..7fe7024f25b3 100644 --- a/core/java/android/os/UpdateEngineCallback.java +++ b/core/java/android/os/UpdateEngineCallback.java @@ -44,5 +44,6 @@ public abstract class UpdateEngineCallback { * unsuccessfully. The value of {@code errorCode} will be one of the * values from {@link UpdateEngine.ErrorCodeConstants}. */ - public abstract void onPayloadApplicationComplete(int errorCode); + public abstract void onPayloadApplicationComplete( + @UpdateEngine.ErrorCode int errorCode); } diff --git a/core/java/android/os/UpdateLock.java b/core/java/android/os/UpdateLock.java index ea273cea8835..036d0951c19a 100644 --- a/core/java/android/os/UpdateLock.java +++ b/core/java/android/os/UpdateLock.java @@ -16,7 +16,7 @@ package android.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.Log; diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 45ee4efa27f7..0ec8658556d0 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -20,8 +20,8 @@ import android.annotation.AppIdInt; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; +import android.compat.annotation.UnsupportedAppUsage; import java.io.PrintWriter; diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index c15618bdaa78..a507e2576df9 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -25,12 +25,12 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index 5769c34c6d20..75b4724c7d26 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.hardware.vibrator.V1_0.EffectStrength; @@ -27,8 +28,6 @@ import android.hardware.vibrator.V1_3.Effect; import android.net.Uri; import android.util.MathUtils; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index 6456d72a4a6f..ae75f3d0d7e6 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -20,8 +20,8 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.AudioAttributes; import android.util.Log; @@ -155,7 +155,7 @@ public abstract class Vibrator { /** * Configure an always-on haptics effect. * - * @param id The board-specific always-on ID to configure. + * @param alwaysOnId The board-specific always-on ID to configure. * @param effect Vibration effect to assign to always-on id. Passing null will disable it. * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or @@ -164,8 +164,17 @@ public abstract class Vibrator { * @hide */ @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) - public boolean setAlwaysOnEffect(int id, @Nullable VibrationEffect effect, - @Nullable AudioAttributes attributes) { + public boolean setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect, + @Nullable AudioAttributes attributes) { + return setAlwaysOnEffect(Process.myUid(), mPackageName, alwaysOnId, effect, attributes); + } + + /** + * @hide + */ + @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) + public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, + @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) { Log.w(TAG, "Always-on effects aren't supported"); return false; } diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java index 825fc64df5cc..684603514f00 100644 --- a/core/java/android/os/WorkSource.java +++ b/core/java/android/os/WorkSource.java @@ -4,9 +4,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.os.WorkSourceProto; import android.provider.Settings; import android.provider.Settings.Global; import android.util.Log; diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index c2d3eccfa3b1..016823e1a07d 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -18,7 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ApplicationInfo; import android.net.LocalSocket; import android.net.LocalSocketAddress; diff --git a/core/java/android/os/health/HealthStatsParceler.java b/core/java/android/os/health/HealthStatsParceler.java index 384342c894d5..f28a9747bc44 100644 --- a/core/java/android/os/health/HealthStatsParceler.java +++ b/core/java/android/os/health/HealthStatsParceler.java @@ -17,11 +17,10 @@ package android.os.health; import android.annotation.TestApi; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import dalvik.annotation.compat.UnsupportedAppUsage; - /** * Class to allow sending the HealthStats through aidl generated glue. * diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java index a92e28a47660..6e259ea2642c 100644 --- a/core/java/android/os/health/SystemHealthManager.java +++ b/core/java/android/os/health/SystemHealthManager.java @@ -17,14 +17,13 @@ package android.os.health; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; import android.os.Build; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.ServiceManager.ServiceNotFoundException; import com.android.internal.app.IBatteryStats; diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java index 921f0f2ab1e2..5cb33615fe22 100644 --- a/core/java/android/os/image/DynamicSystemClient.java +++ b/core/java/android/os/image/DynamicSystemClient.java @@ -256,9 +256,13 @@ public class DynamicSystemClient { mService.send(msg); } catch (RemoteException e) { Slog.e(TAG, "Unable to get status from installation service"); - mExecutor.execute(() -> { + if (mExecutor != null) { + mExecutor.execute(() -> { + mListener.onStatusChanged(STATUS_UNKNOWN, CAUSE_ERROR_IPC, 0, e); + }); + } else { mListener.onStatusChanged(STATUS_UNKNOWN, CAUSE_ERROR_IPC, 0, e); - }); + } } } diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java index 4c92c28c1bfa..cbf531c5730a 100644 --- a/core/java/android/os/image/DynamicSystemManager.java +++ b/core/java/android/os/image/DynamicSystemManager.java @@ -106,9 +106,9 @@ public class DynamicSystemManager { * @return true if the call succeeds */ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) - public boolean startInstallation() { + public boolean startInstallation(String dsuSlot) { try { - return mService.startInstallation(); + return mService.startInstallation(dsuSlot); } catch (RemoteException e) { throw new RuntimeException(e.toString()); } diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl index 69cbab2c68ad..cc32f998d0c2 100644 --- a/core/java/android/os/image/IDynamicSystemService.aidl +++ b/core/java/android/os/image/IDynamicSystemService.aidl @@ -22,9 +22,10 @@ interface IDynamicSystemService { /** * Start DynamicSystem installation. + * @param dsuSlot Name used to identify this installation * @return true if the call succeeds */ - boolean startInstallation(); + boolean startInstallation(@utf8InCpp String dsuSlot); /** * Create a DSU partition. This call may take 60~90 seconds. The caller diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java index b797324c8007..df3c4d55d979 100644 --- a/core/java/android/os/storage/DiskInfo.java +++ b/core/java/android/os/storage/DiskInfo.java @@ -18,7 +18,7 @@ package android.os.storage; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java index 39d5b4529745..9fd9e4e4067d 100644 --- a/core/java/android/os/storage/StorageEventListener.java +++ b/core/java/android/os/storage/StorageEventListener.java @@ -16,7 +16,7 @@ package android.os.storage; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Used for receiving notifications from the StorageManager diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 69c1295df4f9..c7709b988e49 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -40,12 +40,12 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; import android.app.Activity; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java index aefe8430f9de..05b45fa7943c 100644 --- a/core/java/android/os/storage/StorageVolume.java +++ b/core/java/android/os/storage/StorageVolume.java @@ -19,7 +19,7 @@ package android.os.storage; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.net.Uri; diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index 7699a0529826..ff82982bc68b 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -18,7 +18,7 @@ package android.os.storage; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.Resources; diff --git a/core/java/android/os/storage/VolumeRecord.java b/core/java/android/os/storage/VolumeRecord.java index 1a794ebf2a59..c497c8b4fb02 100644 --- a/core/java/android/os/storage/VolumeRecord.java +++ b/core/java/android/os/storage/VolumeRecord.java @@ -16,7 +16,7 @@ package android.os.storage; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.DebugUtils; diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java index 32511e9afbea..dfdb57c4e3f8 100644 --- a/core/java/android/preference/DialogPreference.java +++ b/core/java/android/preference/DialogPreference.java @@ -21,9 +21,9 @@ import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; import android.app.AlertDialog; import android.app.Dialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java index 74c5e3e49d63..af6f18416870 100644 --- a/core/java/android/preference/EditTextPreference.java +++ b/core/java/android/preference/EditTextPreference.java @@ -17,7 +17,7 @@ package android.preference; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.SharedPreferences; import android.content.res.TypedArray; diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java index 830de52576d8..0b648094150f 100644 --- a/core/java/android/preference/ListPreference.java +++ b/core/java/android/preference/ListPreference.java @@ -17,8 +17,8 @@ package android.preference; import android.annotation.ArrayRes; -import android.annotation.UnsupportedAppUsage; import android.app.AlertDialog.Builder; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index e82e60dfe1c4..f508dda00c55 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -21,7 +21,7 @@ import android.annotation.DrawableRes; import android.annotation.LayoutRes; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 47509713d335..ae4a626cdd5d 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -19,13 +19,13 @@ package android.preference; import android.animation.LayoutTransition; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; import android.app.Fragment; import android.app.FragmentBreadCrumbs; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.ListActivity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.Resources; diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java index d6c069f07d22..3f6e5051a3f8 100644 --- a/core/java/android/preference/PreferenceFragment.java +++ b/core/java/android/preference/PreferenceFragment.java @@ -17,10 +17,10 @@ package android.preference; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; import android.app.Activity; import android.app.Fragment; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.TypedArray; diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java index dcc5d4c58784..b263f5041fd6 100644 --- a/core/java/android/preference/PreferenceGroupAdapter.java +++ b/core/java/android/preference/PreferenceGroupAdapter.java @@ -16,7 +16,7 @@ package android.preference; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.drawable.Drawable; import android.os.Handler; import android.preference.Preference.OnPreferenceChangeInternalListener; diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java index f741bd686beb..9d3f349320ad 100644 --- a/core/java/android/preference/PreferenceManager.java +++ b/core/java/android/preference/PreferenceManager.java @@ -18,9 +18,9 @@ package android.preference; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; import android.app.Activity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java index a353dbc8af1b..01fe2f3f6b3a 100644 --- a/core/java/android/preference/PreferenceScreen.java +++ b/core/java/android/preference/PreferenceScreen.java @@ -16,8 +16,8 @@ package android.preference; -import android.annotation.UnsupportedAppUsage; import android.app.Dialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java index 025aad0fcaac..c6d8c08c9141 100644 --- a/core/java/android/preference/RingtonePreference.java +++ b/core/java/android/preference/RingtonePreference.java @@ -16,7 +16,7 @@ package android.preference; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; diff --git a/core/java/android/preference/SeekBarDialogPreference.java b/core/java/android/preference/SeekBarDialogPreference.java index 32ef82103f6c..46be12211fe4 100644 --- a/core/java/android/preference/SeekBarDialogPreference.java +++ b/core/java/android/preference/SeekBarDialogPreference.java @@ -16,7 +16,7 @@ package android.preference; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java index 99ab9dbeb280..a2852bc2cce3 100644 --- a/core/java/android/preference/SeekBarPreference.java +++ b/core/java/android/preference/SeekBarPreference.java @@ -16,7 +16,7 @@ package android.preference; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.os.Parcel; diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 2b3a2ab05e82..5ff98f9d0697 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -17,8 +17,8 @@ package android.preference; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/preference/SwitchPreference.java b/core/java/android/preference/SwitchPreference.java index 9dea1c829713..baa023e41aad 100644 --- a/core/java/android/preference/SwitchPreference.java +++ b/core/java/android/preference/SwitchPreference.java @@ -17,7 +17,7 @@ package android.preference; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java index bb771d721d83..5eb5d17d9bc8 100644 --- a/core/java/android/preference/TwoStatePreference.java +++ b/core/java/android/preference/TwoStatePreference.java @@ -17,7 +17,7 @@ package android.preference; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.SharedPreferences; import android.content.res.TypedArray; diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index a2d5a2312047..6eb524a3886c 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -16,8 +16,8 @@ package android.preference; -import android.annotation.UnsupportedAppUsage; import android.app.Dialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.os.Parcel; diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java index d1b6efc70a2a..7ea5655169e9 100644 --- a/core/java/android/print/PrintDocumentAdapter.java +++ b/core/java/android/print/PrintDocumentAdapter.java @@ -16,7 +16,7 @@ package android.print; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java index 25f383c09ad1..63f38f8a7b4c 100644 --- a/core/java/android/print/PrintJobInfo.java +++ b/core/java/android/print/PrintJobInfo.java @@ -23,7 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Bundle; diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index e1ede93a9ac5..9abce5d46ac6 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -22,9 +22,9 @@ import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.Application.ActivityLifecycleCallbacks; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java index 42570c69650f..75ca7507450f 100644 --- a/core/java/android/print/PrinterId.java +++ b/core/java/android/print/PrinterId.java @@ -17,7 +17,7 @@ package android.print; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java index 30021b488dc5..afa7b80f58a0 100644 --- a/core/java/android/provider/Browser.java +++ b/core/java/android/provider/Browser.java @@ -16,10 +16,8 @@ package android.provider; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -30,8 +28,6 @@ import android.net.Uri; import android.provider.BrowserContract.Bookmarks; import android.provider.BrowserContract.Combined; import android.provider.BrowserContract.History; -import android.provider.BrowserContract.Searches; -import android.util.Log; import android.webkit.WebIconDatabase; public class Browser { diff --git a/core/java/android/provider/BrowserContract.java b/core/java/android/provider/BrowserContract.java index 57dde6693001..5083b8b254ab 100644 --- a/core/java/android/provider/BrowserContract.java +++ b/core/java/android/provider/BrowserContract.java @@ -17,7 +17,7 @@ package android.provider; import android.accounts.Account; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentResolver; diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java index f1d90be9aafe..9c6c92ace483 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -20,11 +20,11 @@ import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.ContentResolver; @@ -40,7 +40,7 @@ import android.database.DatabaseUtils; import android.net.Uri; import android.os.RemoteException; import android.text.format.DateUtils; -import android.text.format.Time; +import android.text.format.TimeMigrationUtils; import android.util.Log; import com.android.internal.util.Preconditions; @@ -1680,7 +1680,7 @@ public final class CalendarContract { * <h3>Writing to Events</h3> There are further restrictions on all Updates * and Inserts in the Events table: * <ul> - * <li>If allDay is set to 1 eventTimezone must be {@link Time#TIMEZONE_UTC} + * <li>If allDay is set to 1 eventTimezone must be "UTC" * and the time must correspond to a midnight boundary.</li> * <li>Exceptions are not allowed to recur. If rrule or rdate is not empty, * original_id and original_sync_id must be empty.</li> @@ -2609,9 +2609,7 @@ public final class CalendarContract { @UnsupportedAppUsage public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) { if (DEBUG) { - Time time = new Time(); - time.set(alarmTime); - String schedTime = time.format(" %a, %b %d, %Y %I:%M%P"); + String schedTime = TimeMigrationUtils.formatMillisWithFixedFormat(alarmTime); Log.d(TAG, "Schedule alarm at " + alarmTime + " " + schedTime); } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 391f3a2fd135..9ffeff99e153 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -17,7 +17,7 @@ package android.provider; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentValues; diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index f10e184ccf5a..524731197cd7 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -21,8 +21,8 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProviderClient; diff --git a/core/java/android/provider/ContactsInternal.java b/core/java/android/provider/ContactsInternal.java index 69c4b9b9abf2..aa2a89cfd612 100644 --- a/core/java/android/provider/ContactsInternal.java +++ b/core/java/android/provider/ContactsInternal.java @@ -15,15 +15,14 @@ */ package android.provider; -import android.annotation.UnsupportedAppUsage; import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.UriMatcher; import android.net.Uri; -import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.widget.Toast; diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index fd81178d2cfb..4bbd213753c2 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -22,7 +22,7 @@ import static com.android.internal.util.Preconditions.checkCollectionNotEmpty; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentInterface; import android.content.ContentResolver; import android.content.Context; diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index 9a384c6d9d79..48410a748766 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -16,8 +16,8 @@ package android.provider; -import android.annotation.UnsupportedAppUsage; import android.app.DownloadManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.NetworkPolicyManager; import android.net.Uri; diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 2299aad6f79a..f6cf1d294765 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -27,9 +27,9 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.AppGlobals; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ContentProviderClient; import android.content.ContentResolver; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e348b5f63a46..1f3ae09e9216 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -37,7 +37,6 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.app.ActivityThread; import android.app.AppOpsManager; @@ -46,6 +45,7 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.SearchManager; import android.app.WallpaperManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentValues; @@ -231,7 +231,9 @@ public final class Settings { * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_TETHER_PROVISIONING = + @SystemApi + @TestApi + public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI"; /** @@ -10441,6 +10443,8 @@ public final class Settings { * is interpreted as |false|. * @hide */ + @SystemApi + @TestApi public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"; /** @@ -15264,8 +15268,9 @@ public final class Settings { * current time. * @hide */ - public static boolean checkAndNoteWriteSettingsOperation(Context context, int uid, - String callingPackage, boolean throwException) { + @SystemApi + public static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, + @NonNull String callingPackage, boolean throwException) { return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS, PM_WRITE_SETTINGS, true); diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index df36f143393b..90ac821363b2 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -24,7 +24,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentValues; @@ -35,6 +35,7 @@ import android.database.Cursor; import android.database.sqlite.SqliteWrapper; import android.net.Uri; import android.os.Build; +import android.os.Bundle; import android.os.Parcel; import android.telephony.Rlog; import android.telephony.ServiceState; @@ -3522,7 +3523,8 @@ public final class Telephony { * can manage DPC-owned APNs. * @hide */ - public static final Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc"); + @SystemApi + public static final @NonNull Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc"); /** * The {@code content://} style URL to be called from Telephony to query APNs. @@ -3831,6 +3833,13 @@ public final class Telephony { public static final String USER_EDITABLE = "user_editable"; /** + * Integer value denoting an invalid APN id + * @hide + */ + @SystemApi + public static final int INVALID_APN_ID = -1; + + /** * {@link #EDITED_STATUS APN edit status} indicates that this APN has not been edited or * fails to edit. * <p>Type: INTEGER </p> @@ -4050,6 +4059,108 @@ public final class Telephony { public static final Uri MESSAGE_HISTORY_URI = Uri.parse("content://cellbroadcasts/history"); /** + * The authority for the legacy cellbroadcast provider. + * This is used for OEM data migration. OEMs want to migrate message history or + * sharepreference data to mainlined cellbroadcastreceiver app, should have a + * contentprovider with authority: cellbroadcast-legacy. Mainlined cellbroadcastreceiver + * will interact with this URI to retrieve data and persists to mainlined cellbroadcast app. + * + * @hide + */ + @SystemApi + public static final @NonNull String AUTHORITY_LEGACY = "cellbroadcast-legacy"; + + /** + * A content:// style uri to the authority for the legacy cellbroadcast provider. + * @hide + */ + @SystemApi + public static final @NonNull Uri AUTHORITY_LEGACY_URI = + Uri.parse("content://cellbroadcast-legacy"); + + /** + * Method name to {@link android.content.ContentProvider#call(String, String, Bundle) + * for {@link #AUTHORITY_LEGACY}. Used to query cellbroadcast {@link Preference}, + * containing following supported entries + * <ul> + * <li>{@link #ENABLE_AREA_UPDATE_INFO_PREF}</li> + * <li>{@link #ENABLE_TEST_ALERT_PREF}</li> + * <li>{@link #ENABLE_STATE_LOCAL_TEST_PREF}</li> + * <li>{@link #ENABLE_PUBLIC_SAFETY_PREF}</li> + * <li>{@link #ENABLE_CMAS_AMBER_PREF}</li> + * <li>{@link #ENABLE_CMAS_SEVERE_THREAT_PREF}</li> + * <li>{@link #ENABLE_CMAS_EXTREME_THREAT_PREF}</li> + * <li>{@link #ENABLE_CMAS_PRESIDENTIAL_PREF}</li> + * <li>{@link #ENABLE_ALERT_VIBRATION_PREF}</li> + * <li>{@link #ENABLE_EMERGENCY_PERF}</li> + * <li>{@link #ENABLE_CMAS_IN_SECOND_LANGUAGE_PREF}</li> + * </ul> + * @hide + */ + @SystemApi + public static final @NonNull String CALL_METHOD_GET_PREFERENCE = "get_preference"; + + /** + * Arg name to {@link android.content.ContentProvider#call(String, String, Bundle)} + * for {@link #AUTHORITY_LEGACY}. + * Contains all supported shared preferences for cellbroadcast. + * + * @hide + */ + @SystemApi + public static final class Preference { + /** + * Not Instantiatable. + * @hide + */ + private Preference() {} + + /** Preference to enable area update info alert */ + public static final @NonNull String ENABLE_AREA_UPDATE_INFO_PREF = + "enable_area_update_info_alerts"; + + /** Preference to enable test alert */ + public static final @NonNull String ENABLE_TEST_ALERT_PREF = + "enable_test_alerts"; + + /** Preference to enable state local test alert */ + public static final @NonNull String ENABLE_STATE_LOCAL_TEST_PREF + = "enable_state_local_test_alerts"; + + /** Preference to enable public safety alert */ + public static final @NonNull String ENABLE_PUBLIC_SAFETY_PREF + = "enable_public_safety_messages"; + + /** Preference to enable amber alert */ + public static final @NonNull String ENABLE_CMAS_AMBER_PREF + = "enable_cmas_amber_alerts"; + + /** Preference to enable severe threat alert */ + public static final @NonNull String ENABLE_CMAS_SEVERE_THREAT_PREF + = "enable_cmas_severe_threat_alerts"; + + /** Preference to enable extreme threat alert */ + public static final @NonNull String ENABLE_CMAS_EXTREME_THREAT_PREF = + "enable_cmas_extreme_threat_alerts"; + + /** Preference to enable presidential alert */ + public static final @NonNull String ENABLE_CMAS_PRESIDENTIAL_PREF = + "enable_cmas_presidential_alerts"; + + /** Preference to enable alert vibration */ + public static final @NonNull String ENABLE_ALERT_VIBRATION_PREF = + "enable_alert_vibrate"; + + /** Preference to enable emergency alert */ + public static final @NonNull String ENABLE_EMERGENCY_PERF = + "enable_emergency_alerts"; + + /** Preference to enable receive alerts in second language */ + public static final @NonNull String ENABLE_CMAS_IN_SECOND_LANGUAGE_PREF = + "receive_cmas_in_second_language"; + } + + /** * The subscription which received this cell broadcast message. * <P>Type: INTEGER</P> */ diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java index d646e23d230a..a5c5c613e1f2 100644 --- a/core/java/android/se/omapi/SEService.java +++ b/core/java/android/se/omapi/SEService.java @@ -22,14 +22,11 @@ package android.se.omapi; -import android.app.ActivityThread; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; @@ -101,6 +98,8 @@ public final class SEService { private static final String TAG = "OMAPI.SEService"; + private static final String UICC_TERMINAL = "SIM"; + private final Object mLock = new Object(); /** The client context (e.g. activity). */ @@ -143,10 +142,6 @@ public final class SEService { throw new NullPointerException("Arguments must not be null"); } - if (!hasOMAPIReaders()) { - throw new UnsupportedOperationException("Device does not support any OMAPI reader"); - } - mContext = context; mSEListener.mListener = listener; mSEListener.mExecutor = executor; @@ -197,32 +192,33 @@ public final class SEService { * is of length 0. */ public @NonNull Reader[] getReaders() { - if (mSecureElementService == null) { - throw new IllegalStateException("service not connected to system"); - } - String[] readerNames; - try { - readerNames = mSecureElementService.getReaders(); - } catch (RemoteException e) { - throw new RuntimeException(e); - } + loadReaders(); - Reader[] readers = new Reader[readerNames.length]; - int i = 0; - for (String readerName : readerNames) { - if (mReaders.get(readerName) == null) { - try { - mReaders.put(readerName, new Reader(this, readerName, - getReader(readerName))); - readers[i++] = mReaders.get(readerName); - } catch (Exception e) { - Log.e(TAG, "Error adding Reader: " + readerName, e); - } - } else { - readers[i++] = mReaders.get(readerName); - } - } - return readers; + return mReaders.values().toArray(new Reader[0]); + } + + /** + * Obtain a UICC Reader instance with specific slot number from the SecureElementService + * + * @param slotNumber The index of the uicc slot. The index starts from 1. + * @throws IllegalArgumentException if the reader object corresponding to the uiccSlotNumber + * is not exist. + * @return A Reader object for this uicc slot. + */ + public @NonNull Reader getUiccReader(int slotNumber) { + if (slotNumber < 1) { + throw new IllegalArgumentException("slotNumber should be larger than 0"); + } + loadReaders(); + + String readerName = UICC_TERMINAL + slotNumber; + Reader reader = mReaders.get(readerName); + + if (reader == null) { + throw new IllegalArgumentException("Reader:" + readerName + " doesn't exist"); + } + + return reader; } /** @@ -279,21 +275,28 @@ public final class SEService { } /** - * Helper to check if this device support any OMAPI readers + * Load available Secure Element Readers */ - private static boolean hasOMAPIReaders() { - IPackageManager pm = ActivityThread.getPackageManager(); - if (pm == null) { - Log.e(TAG, "Cannot get package manager, assuming OMAPI readers supported"); - return true; + private void loadReaders() { + if (mSecureElementService == null) { + throw new IllegalStateException("service not connected to system"); } + String[] readerNames; try { - return pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_UICC, 0) - || pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_ESE, 0) - || pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_SD, 0); + readerNames = mSecureElementService.getReaders(); } catch (RemoteException e) { - Log.e(TAG, "Package manager query failed, assuming OMAPI readers supported", e); - return true; + throw e.rethrowAsRuntimeException(); + } + + for (String readerName : readerNames) { + if (mReaders.get(readerName) == null) { + try { + mReaders.put(readerName, new Reader(this, readerName, + getReader(readerName))); + } catch (Exception e) { + Log.e(TAG, "Error adding Reader: " + readerName, e); + } + } } } } diff --git a/core/java/android/security/KeystoreArguments.java b/core/java/android/security/KeystoreArguments.java index e634234493e3..a59c4e04285d 100644 --- a/core/java/android/security/KeystoreArguments.java +++ b/core/java/android/security/KeystoreArguments.java @@ -16,7 +16,7 @@ package android.security; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/security/keymaster/ExportResult.java b/core/java/android/security/keymaster/ExportResult.java index 1be5ae90d911..037b85270306 100644 --- a/core/java/android/security/keymaster/ExportResult.java +++ b/core/java/android/security/keymaster/ExportResult.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java index 2eb2cefc3617..d8382fa8f969 100644 --- a/core/java/android/security/keymaster/KeyCharacteristics.java +++ b/core/java/android/security/keymaster/KeyCharacteristics.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java index d2dbdec7f726..e009e128bfea 100644 --- a/core/java/android/security/keymaster/KeymasterArguments.java +++ b/core/java/android/security/keymaster/KeymasterArguments.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/security/keymaster/KeymasterBlob.java b/core/java/android/security/keymaster/KeymasterBlob.java index 6a2024f0feb6..68365bfe603f 100644 --- a/core/java/android/security/keymaster/KeymasterBlob.java +++ b/core/java/android/security/keymaster/KeymasterBlob.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java index fc562bd2174e..81b08c5b5b0a 100644 --- a/core/java/android/security/keymaster/KeymasterBlobArgument.java +++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; /** diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java index 4286aa0d4ae3..25b2ac409d97 100644 --- a/core/java/android/security/keymaster/KeymasterBooleanArgument.java +++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; /** diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java index 3e04c1543117..218f4880b289 100644 --- a/core/java/android/security/keymaster/KeymasterDateArgument.java +++ b/core/java/android/security/keymaster/KeymasterDateArgument.java @@ -16,8 +16,9 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; + import java.util.Date; /** diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java index 4aadce458395..01d38c799d9c 100644 --- a/core/java/android/security/keymaster/KeymasterIntArgument.java +++ b/core/java/android/security/keymaster/KeymasterIntArgument.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; /** diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java index bc2255e22a69..3ac27ccef295 100644 --- a/core/java/android/security/keymaster/KeymasterLongArgument.java +++ b/core/java/android/security/keymaster/KeymasterLongArgument.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; /** diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java index c278eb3b85fd..b4e155a527de 100644 --- a/core/java/android/security/keymaster/OperationResult.java +++ b/core/java/android/security/keymaster/OperationResult.java @@ -16,7 +16,7 @@ package android.security.keymaster; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java index d8936d948ead..58dc4ba8df21 100644 --- a/core/java/android/security/net/config/RootTrustManager.java +++ b/core/java/android/security/net/config/RootTrustManager.java @@ -16,15 +16,16 @@ package android.security.net.config; +import android.compat.annotation.UnsupportedAppUsage; + import java.net.Socket; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.List; -import android.annotation.UnsupportedAppUsage; -import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; import javax.net.ssl.X509ExtendedTrustManager; /** diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 38de79456bee..de4a5511fcdb 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -21,9 +21,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; import android.app.AlarmManager; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index b44c9d59ebe5..5da34a343513 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -22,7 +22,6 @@ import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.INotificationManager; import android.app.Notification; @@ -33,6 +32,7 @@ import android.app.NotificationManager; import android.app.Person; import android.app.Service; import android.companion.CompanionDeviceManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index 905c7811e457..d8ea971ced29 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -17,10 +17,10 @@ package android.service.notification; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.Notification; import android.app.NotificationManager; import android.app.Person; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 93bcdbffd133..9e7af1f41a87 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -20,11 +20,11 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCRE import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.NotificationManager; import android.app.NotificationManager.Policy; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index bd953cad2b75..e6b19224cce4 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -19,8 +19,8 @@ package android.service.voice; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.KeyphraseEnrollmentInfo; @@ -32,7 +32,6 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra; import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; -import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; import android.media.AudioFormat; import android.os.AsyncTask; import android.os.Handler; diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 0de17ca3b960..36e057f4a97d 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -18,8 +18,8 @@ package android.service.voice; import android.annotation.NonNull; import android.annotation.SdkConstant; -import android.annotation.UnsupportedAppUsage; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/service/vr/VrListenerService.java b/core/java/android/service/vr/VrListenerService.java index 3c384955a578..2758ace8d00b 100644 --- a/core/java/android/service/vr/VrListenerService.java +++ b/core/java/android/service/vr/VrListenerService.java @@ -18,9 +18,9 @@ package android.service.vr; import android.annotation.NonNull; import android.annotation.SdkConstant; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/service/wallpaper/Android.bp b/core/java/android/service/wallpaper/Android.bp index aa6123f5a983..ffbdb035c36c 100644 --- a/core/java/android/service/wallpaper/Android.bp +++ b/core/java/android/service/wallpaper/Android.bp @@ -6,6 +6,8 @@ android_library { "I*.aidl", ], + libs: ["unsupportedappusage"], + // Enforce that the library is built against java 8 so that there are // no compatibility issues with launcher java_version: "1.8", diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index d645e3f746d7..3cb3ec3e25f5 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -20,11 +20,11 @@ import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.Service; import android.app.WallpaperColors; import android.app.WallpaperInfo; import android.app.WallpaperManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 100774c896ca..f3650d6834c8 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -20,7 +20,7 @@ import android.annotation.Nullable; import android.annotation.RawRes; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java index 2fab40472bd5..a8aea7c1eb59 100644 --- a/core/java/android/speech/tts/TtsEngines.java +++ b/core/java/android/speech/tts/TtsEngines.java @@ -18,7 +18,7 @@ package android.speech.tts; import static android.provider.Settings.Secure.getString; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index 146c1c3b6123..f886cf58b850 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -21,10 +21,9 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Build; -import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; @@ -179,6 +178,10 @@ public class PhoneStateListener { * Listen for {@link android.telephony.Annotation.PreciseCallStates} of ringing, * background and foreground calls. * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * * @hide */ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) @@ -188,13 +191,13 @@ public class PhoneStateListener { /** * Listen for {@link PreciseDataConnectionState} on the data connection (cellular). * - * <p>Requires permission {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} * or the calling app has carrier privileges * (see {@link TelephonyManager#hasCarrierPrivileges}). * * @see #onPreciseDataConnectionStateChanged */ - @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE)) + @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 0x00001000; /** @@ -319,26 +322,36 @@ public class PhoneStateListener { * Listen for call disconnect causes which contains {@link DisconnectCause} and * {@link PreciseDisconnectCause}. * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * */ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) public static final int LISTEN_CALL_DISCONNECT_CAUSES = 0x02000000; /** * Listen for changes to the call attributes of a currently active call. - * {@more} - * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE - * READ_PRECISE_PHONE_STATE} + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). * * @see #onCallAttributesChanged * @hide */ @SystemApi + @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 0x04000000; /** * Listen for IMS call disconnect causes which contains * {@link android.telephony.ims.ImsReasonInfo} * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * * @see #onImsCallDisconnectCauseChanged(ImsReasonInfo) */ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) @@ -370,6 +383,21 @@ public class PhoneStateListener { @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 0x20000000; + /** + * Listen for Registration Failures. + * + * Listen for indications that a registration procedure has failed in either the CS or PS + * domain. This indication does not necessarily indicate a change of service state, which should + * be tracked via {@link #LISTEN_SERVICE_STATE}. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling + * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see #onRegistrationFailed() + */ + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000; + /* * Subscription used to listen to the phone state changes * @hide @@ -933,6 +961,38 @@ public class PhoneStateListener { } /** + * Report that Registration or a Location/Routing/Tracking Area update has failed. + * + * <p>Indicate whenever a registration procedure, including a location, routing, or tracking + * area update fails. This includes procedures that do not necessarily result in a change of + * the modem's registration status. If the modem's registration status changes, that is + * reflected in the onNetworkStateChanged() and subsequent get{Voice/Data}RegistrationState(). + * + * <p>Because registration failures are ephemeral, this callback is not sticky. + * Registrants will not receive the most recent past value when registering. + * + * @param cellIdentity the CellIdentity, which must include the globally unique identifier + * for the cell (for example, all components of the CGI or ECGI). + * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the + * cell that was chosen for the failed registration attempt. + * @param domain DOMAIN_CS, DOMAIN_PS or both in case of a combined procedure. + * @param causeCode the primary failure cause code of the procedure. + * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95 + * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147 + * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9 + * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2 + * Integer.MAX_VALUE if this value is unused. + * @param additionalCauseCode the cause code of any secondary/combined procedure if appropriate. + * For UMTS, if a combined attach succeeds for PS only, then the GMM cause code shall be + * included as an additionalCauseCode. For LTE (ESM), cause codes are in + * TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused. + */ + public void onRegistrationFailed(@NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn, + @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) { + // default implementation empty + } + + /** * The callback methods need to be called on the handler thread where * this object was created. If the binder did that for us it'd be nice. * @@ -984,8 +1044,11 @@ public class PhoneStateListener { () -> mExecutor.execute(() -> psl.onCallForwardingIndicatorChanged(cfi))); } - public void onCellLocationChanged(Bundle bundle) { - CellLocation location = CellLocation.newFromBundle(bundle); + public void onCellLocationChanged(CellIdentity cellIdentity) { + // There is no system/public API to create an CellIdentity in system server, + // so the server pass a null to indicate an empty initial location. + CellLocation location = + cellIdentity == null ? CellLocation.getEmpty() : cellIdentity.asCellLocation(); PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); if (psl == null) return; @@ -1201,6 +1264,18 @@ public class PhoneStateListener { () -> psl.onImsCallDisconnectCauseChanged(disconnectCause))); } + + public void onRegistrationFailed(@NonNull CellIdentity cellIdentity, + @NonNull String chosenPlmn, @NetworkRegistrationInfo.Domain int domain, + int causeCode, int additionalCauseCode) { + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onRegistrationFailed( + cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode))); + // default implementation empty + } } diff --git a/core/java/android/telephony/Rlog.java b/core/java/android/telephony/Rlog.java index cdab2dc54dd2..2afdd339e80b 100644 --- a/core/java/android/telephony/Rlog.java +++ b/core/java/android/telephony/Rlog.java @@ -16,12 +16,11 @@ package android.telephony; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.text.TextUtils; -import android.util.Log; - -import android.annotation.UnsupportedAppUsage; import android.util.Base64; +import android.util.Log; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java index ec2050fb1a44..28a5c2086ede 100644 --- a/core/java/android/telephony/SubscriptionPlan.java +++ b/core/java/android/telephony/SubscriptionPlan.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation.NetworkType; import android.util.Range; import android.util.RecurrenceRule; @@ -33,6 +34,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Period; import java.time.ZonedDateTime; +import java.util.Arrays; import java.util.Iterator; import java.util.Objects; @@ -42,6 +44,14 @@ import java.util.Objects; * as explaining how much mobile data they have remaining, and what will happen * when they run out. * + * If specifying network types, the developer must supply at least one plan + * that applies to all network types (default), and all additional plans + * may not include a particular network type more than once. + * This is enforced by {@link SubscriptionManager} when setting the plans. + * + * Plan selection will prefer plans that have specific network types defined + * over plans that apply to all network types. + * * @see SubscriptionManager#setSubscriptionPlans(int, java.util.List) * @see SubscriptionManager#getSubscriptionPlans(int) */ @@ -80,6 +90,8 @@ public final class SubscriptionPlan implements Parcelable { private int dataLimitBehavior = LIMIT_BEHAVIOR_UNKNOWN; private long dataUsageBytes = BYTES_UNKNOWN; private long dataUsageTime = TIME_UNKNOWN; + private @NetworkType int[] networkTypes; + private long networkTypesBitMask; private SubscriptionPlan(RecurrenceRule cycleRule) { this.cycleRule = Preconditions.checkNotNull(cycleRule); @@ -93,6 +105,7 @@ public final class SubscriptionPlan implements Parcelable { dataLimitBehavior = source.readInt(); dataUsageBytes = source.readLong(); dataUsageTime = source.readLong(); + networkTypes = source.createIntArray(); } @Override @@ -109,6 +122,7 @@ public final class SubscriptionPlan implements Parcelable { dest.writeInt(dataLimitBehavior); dest.writeLong(dataUsageBytes); dest.writeLong(dataUsageTime); + dest.writeIntArray(networkTypes); } @Override @@ -121,13 +135,14 @@ public final class SubscriptionPlan implements Parcelable { .append(" dataLimitBehavior=").append(dataLimitBehavior) .append(" dataUsageBytes=").append(dataUsageBytes) .append(" dataUsageTime=").append(dataUsageTime) + .append(" networkTypes=").append(Arrays.toString(networkTypes)) .append("}").toString(); } @Override public int hashCode() { return Objects.hash(cycleRule, title, summary, dataLimitBytes, dataLimitBehavior, - dataUsageBytes, dataUsageTime); + dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes)); } @Override @@ -140,7 +155,8 @@ public final class SubscriptionPlan implements Parcelable { && dataLimitBytes == other.dataLimitBytes && dataLimitBehavior == other.dataLimitBehavior && dataUsageBytes == other.dataUsageBytes - && dataUsageTime == other.dataUsageTime; + && dataUsageTime == other.dataUsageTime + && Arrays.equals(networkTypes, other.networkTypes); } return false; } @@ -204,6 +220,32 @@ public final class SubscriptionPlan implements Parcelable { } /** + * Return an array containing all {@link NetworkType}s this SubscriptionPlan applies to. + * A null value means this SubscriptionPlan applies to all network types. + */ + public @Nullable @NetworkType int[] getNetworkTypes() { + return networkTypes; + } + + /** + * Return the networkTypes array converted to a {@link TelephonyManager.NetworkTypeBitMask} + * @hide + */ + public long getNetworkTypesBitMask() { + // calculate bitmask the first time and save for future calls + if (networkTypesBitMask == 0) { + if (networkTypes == null) { + networkTypesBitMask = ~0; + } else { + for (int networkType : networkTypes) { + networkTypesBitMask |= TelephonyManager.getBitMaskForNetworkType(networkType); + } + } + } + return networkTypesBitMask; + } + + /** * Return an iterator that will return all valid data usage cycles based on * any recurrence rules. The iterator starts from the currently active cycle * and walks backwards through time. @@ -335,5 +377,17 @@ public final class SubscriptionPlan implements Parcelable { plan.dataUsageTime = dataUsageTime; return this; } + + /** + * Set the network types this SubscriptionPlan applies to. + * + * @param networkTypes a set of all {@link NetworkType}s that apply to this plan. + * A null value means the plan applies to all network types, + * and an empty array means the plan applies to no network types. + */ + public @NonNull Builder setNetworkTypes(@Nullable @NetworkType int[] networkTypes) { + plan.networkTypes = networkTypes; + return this; + } } } diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index c11a99d231d5..a2422948ca86 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -22,7 +22,6 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; import android.os.Binder; -import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.Annotation.CallState; @@ -116,7 +115,8 @@ public class TelephonyRegistryManager { }; mSubscriptionChangedListenerMap.put(listener, callback); try { - sRegistry.addOnSubscriptionsChangedListener(mContext.getOpPackageName(), callback); + sRegistry.addOnSubscriptionsChangedListener(mContext.getOpPackageName(), + null, callback); } catch (RemoteException ex) { // system server crash } @@ -175,7 +175,7 @@ public class TelephonyRegistryManager { mOpportunisticSubscriptionChangedListenerMap.put(listener, callback); try { sRegistry.addOnOpportunisticSubscriptionsChangedListener(mContext.getOpPackageName(), - callback); + null, callback); } catch (RemoteException ex) { // system server crash } @@ -621,9 +621,9 @@ public class TelephonyRegistryManager { * Notify call disconnect causes which contains {@link DisconnectCause} and {@link * android.telephony.PreciseDisconnectCause}. * - * @param subId for which call disconnected. * @param slotIndex for which call disconnected. Can be derived from subId except when subId is * invalid. + * @param subId for which call disconnected. * @param cause {@link DisconnectCause} for the disconnected call. * @param preciseCause {@link android.telephony.PreciseDisconnectCause} for the disconnected * call. @@ -639,10 +639,14 @@ public class TelephonyRegistryManager { } /** - * TODO change from bundle to CellLocation? + * Notify {@link android.telephony.CellLocation} changed. + * + * <p>To be compatible with {@link TelephonyRegistry}, use {@link CellIdentity} which is + * parcelable, and convert to CellLocation in client code. + * * @hide */ - public void notifyCellLocation(int subId, Bundle cellLocation) { + public void notifyCellLocation(int subId, CellIdentity cellLocation) { try { sRegistry.notifyCellLocationForSubscriber(subId, cellLocation); } catch (RemoteException ex) { @@ -678,4 +682,36 @@ public class TelephonyRegistryManager { } } + + /** + * Report that Registration or a Location/Routing/Tracking Area update has failed. + * + * @param slotIndex for which call disconnected. Can be derived from subId except when subId is + * invalid. + * @param subId for which cellinfo changed. + * @param cellIdentity the CellIdentity, which must include the globally unique identifier + * for the cell (for example, all components of the CGI or ECGI). + * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the + * cell that was chosen for the failed registration attempt. + * @param domain DOMAIN_CS, DOMAIN_PS or both in case of a combined procedure. + * @param causeCode the primary failure cause code of the procedure. + * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95 + * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147 + * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9 + * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2 + * Integer.MAX_VALUE if this value is unused. + * @param additionalCauseCode the cause code of any secondary/combined procedure if appropriate. + * For UMTS, if a combined attach succeeds for PS only, then the GMM cause code shall be + * included as an additionalCauseCode. For LTE (ESM), cause codes are in + * TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused. + */ + public void notifyRegistrationFailed(int slotIndex, int subId, + @NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn, + @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) { + try { + sRegistry.notifyRegistrationFailed(slotIndex, subId, cellIdentity, + chosenPlmn, domain, causeCode, additionalCauseCode); + } catch (RemoteException ex) { + } + } } diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java index bb7fb446d40c..f1e2181a8538 100644 --- a/core/java/android/text/AndroidBidi.java +++ b/core/java/android/text/AndroidBidi.java @@ -16,7 +16,7 @@ package android.text; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.icu.lang.UCharacter; import android.icu.lang.UCharacterDirection; import android.icu.lang.UProperty; diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java index cf6987c6d123..3ee1a9000188 100644 --- a/core/java/android/text/BoringLayout.java +++ b/core/java/android/text/BoringLayout.java @@ -16,7 +16,7 @@ package android.text; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index 32982f9df15d..c60d446d921d 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -20,7 +20,7 @@ import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Paint; import android.graphics.Rect; import android.os.Build; diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java index 19c55d5f497d..b5688a48344e 100644 --- a/core/java/android/text/FontConfig.java +++ b/core/java/android/text/FontConfig.java @@ -21,7 +21,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.fonts.FontVariationAxis; import android.net.Uri; diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index 18f8db23db74..55af087ca5b8 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -16,9 +16,9 @@ package android.text; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.Application; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Typeface; diff --git a/core/java/android/text/InputFilter.java b/core/java/android/text/InputFilter.java index a9a7b2f2fa7a..96e7bd0fef4c 100644 --- a/core/java/android/text/InputFilter.java +++ b/core/java/android/text/InputFilter.java @@ -17,7 +17,7 @@ package android.text; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.Preconditions; diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 2c2c2953ed51..8a4497a0f0ce 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -18,7 +18,7 @@ package android.text; import android.annotation.IntDef; import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java index 68199a4f622e..57c1d237d4ed 100644 --- a/core/java/android/text/Selection.java +++ b/core/java/android/text/Selection.java @@ -17,7 +17,7 @@ package android.text; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.text.BreakIterator; diff --git a/core/java/android/text/SpanSet.java b/core/java/android/text/SpanSet.java index 362825a005e9..81bdd65974a8 100644 --- a/core/java/android/text/SpanSet.java +++ b/core/java/android/text/SpanSet.java @@ -16,7 +16,8 @@ package android.text; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.lang.reflect.Array; import java.util.Arrays; diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index 0d29da00f7c9..ac27e3d10c4f 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -17,7 +17,7 @@ package android.text; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.BaseCanvas; import android.graphics.Paint; import android.util.Log; diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java index a9866335f271..b85ef76bd2d5 100644 --- a/core/java/android/text/SpannableStringInternal.java +++ b/core/java/android/text/SpannableStringInternal.java @@ -16,7 +16,7 @@ package android.text; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 69cfc03a7ff8..85e2d98e93c0 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -20,7 +20,7 @@ import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Paint; import android.graphics.text.LineBreaker; import android.os.Build; diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 1c50d73c4953..3c51fa765263 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -19,7 +19,7 @@ package android.text; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java index d5aad33a85e7..73825b13cb6b 100644 --- a/core/java/android/text/TextPaint.java +++ b/core/java/android/text/TextPaint.java @@ -18,7 +18,7 @@ package android.text; import android.annotation.ColorInt; import android.annotation.Px; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Paint; /** diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 81643e90428f..788d98bbf3eb 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -24,7 +24,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.PluralsRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.icu.lang.UCharacter; diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index 3c8de94c05f2..0863a813543c 100755 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -17,9 +17,8 @@ package android.text.format; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.os.UserHandle; import android.provider.Settings; import android.text.SpannableStringBuilder; import android.text.Spanned; diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 906251837ade..f236f19e973f 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -16,7 +16,7 @@ package android.text.format; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index d7baa1086b2f..17d3ae4a7ff0 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -18,7 +18,7 @@ package android.text.format; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.icu.text.MeasureFormat; diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java index 5a14092c95a8..f7fd89d7d819 100644 --- a/core/java/android/text/format/TimeFormatter.java +++ b/core/java/android/text/format/TimeFormatter.java @@ -26,6 +26,9 @@ import libcore.icu.LocaleData; import libcore.util.ZoneInfo; import java.nio.CharBuffer; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.Formatter; import java.util.Locale; import java.util.TimeZone; @@ -86,6 +89,59 @@ class TimeFormatter { } /** + * The implementation of {@link TimeMigrationUtils#formatMillisWithFixedFormat(long)} for + * 2038-safe formatting with the pattern "%Y-%m-%d %H:%M:%S" and including the historic + * incorrect digit localization behavior. + */ + String formatMillisWithFixedFormat(long timeMillis) { + // This method is deliberately not a general purpose replacement for + // format(String, ZoneInfo.WallTime, ZoneInfo): It hard-codes the pattern used; many of the + // pattern characters supported by Time.format() have unusual behavior which would make + // using java.time.format or similar packages difficult. It would be a lot of work to share + // behavior and many internal Android usecases can be covered by this common pattern + // behavior. + + // No need to worry about overflow / underflow: long millis is representable by Instant and + // LocalDateTime with room to spare. + Instant instant = Instant.ofEpochMilli(timeMillis); + + // Date/times are calculated in the current system default time zone. + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + + // You'd think it would be as simple as: + // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", locale); + // return formatter.format(localDateTime); + // but we retain Time's behavior around digits. + + StringBuilder stringBuilder = new StringBuilder(19); + + // This effectively uses the US locale because number localization is handled separately + // (see below). + stringBuilder.append(localDateTime.getYear()); + stringBuilder.append('-'); + append2DigitNumber(stringBuilder, localDateTime.getMonthValue()); + stringBuilder.append('-'); + append2DigitNumber(stringBuilder, localDateTime.getDayOfMonth()); + stringBuilder.append(' '); + append2DigitNumber(stringBuilder, localDateTime.getHour()); + stringBuilder.append(':'); + append2DigitNumber(stringBuilder, localDateTime.getMinute()); + stringBuilder.append(':'); + append2DigitNumber(stringBuilder, localDateTime.getSecond()); + + String result = stringBuilder.toString(); + return localizeDigits(result); + } + + /** Zero-pads value as needed to achieve a 2-digit number. */ + private static void append2DigitNumber(StringBuilder builder, int value) { + if (value < 10) { + builder.append('0'); + } + builder.append(value); + } + + /** * Format the specified {@code wallTime} using {@code pattern}. The output is returned. */ public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { @@ -99,12 +155,9 @@ class TimeFormatter { formatInternal(pattern, wallTime, zoneInfo); String result = stringBuilder.toString(); - // This behavior is the source of a bug since some formats are defined as being - // in ASCII and not localized. - if (localeData.zeroDigit != '0') { - result = localizeDigits(result); - } - return result; + // The localizeDigits() behavior is the source of a bug since some formats are defined + // as being in ASCII and not localized. + return localizeDigits(result); } finally { outputBuilder = null; numberFormatter = null; @@ -112,6 +165,10 @@ class TimeFormatter { } private String localizeDigits(String s) { + if (localeData.zeroDigit == '0') { + return s; + } + int length = s.length(); int offsetToLocalizedDigits = localeData.zeroDigit - '0'; StringBuilder result = new StringBuilder(length); diff --git a/core/java/android/text/format/TimeMigrationUtils.java b/core/java/android/text/format/TimeMigrationUtils.java new file mode 100644 index 000000000000..17bac8d67b26 --- /dev/null +++ b/core/java/android/text/format/TimeMigrationUtils.java @@ -0,0 +1,40 @@ +/* + * 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.text.format; + +/** + * Logic to ease migration away from {@link Time} in Android internal code. {@link Time} is + * afflicted by the Y2038 issue and deprecated. The methods here are intended to allow minimal + * changes to classes that use {@link Time} for common behavior. + * + * @hide + */ +public class TimeMigrationUtils { + + private TimeMigrationUtils() {} + + /** + * A Y2038-safe replacement for various users of the {@link Time#format(String)} with the + * pattern "%Y-%m-%d %H:%M:%S". Note, this method retains the unusual localization behavior + * originally implemented by Time, which can lead to non-latin numbers being produced if the + * default locale does not use latin numbers. + */ + public static String formatMillisWithFixedFormat(long timeMillis) { + // Delegate to TimeFormatter so that the unusual localization / threading behavior can be + // reused. + return new TimeFormatter().formatMillisWithFixedFormat(timeMillis); + } +} diff --git a/core/java/android/text/method/AllCapsTransformationMethod.java b/core/java/android/text/method/AllCapsTransformationMethod.java index 5a7c98d7ccdf..305b056aee72 100644 --- a/core/java/android/text/method/AllCapsTransformationMethod.java +++ b/core/java/android/text/method/AllCapsTransformationMethod.java @@ -17,7 +17,7 @@ package android.text.method; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.text.Spanned; diff --git a/core/java/android/text/method/HideReturnsTransformationMethod.java b/core/java/android/text/method/HideReturnsTransformationMethod.java index 440a4b187173..40ce8714cf38 100644 --- a/core/java/android/text/method/HideReturnsTransformationMethod.java +++ b/core/java/android/text/method/HideReturnsTransformationMethod.java @@ -16,7 +16,7 @@ package android.text.method; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; /** diff --git a/core/java/android/text/method/LinkMovementMethod.java b/core/java/android/text/method/LinkMovementMethod.java index a0c44a8b6bdc..c544c41c38a9 100644 --- a/core/java/android/text/method/LinkMovementMethod.java +++ b/core/java/android/text/method/LinkMovementMethod.java @@ -16,7 +16,7 @@ package android.text.method; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.text.Layout; import android.text.NoCopySpan; diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java index ec7ed34bb5ba..d1d7c968411f 100644 --- a/core/java/android/text/method/MetaKeyKeyListener.java +++ b/core/java/android/text/method/MetaKeyKeyListener.java @@ -16,7 +16,7 @@ package android.text.method; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.text.Editable; import android.text.NoCopySpan; import android.text.Spannable; diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java index c96fc5de0845..53553be6e5a8 100644 --- a/core/java/android/text/method/PasswordTransformationMethod.java +++ b/core/java/android/text/method/PasswordTransformationMethod.java @@ -16,7 +16,7 @@ package android.text.method; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/text/method/TransformationMethod2.java b/core/java/android/text/method/TransformationMethod2.java index 0bf401a84df0..8d5ec246640e 100644 --- a/core/java/android/text/method/TransformationMethod2.java +++ b/core/java/android/text/method/TransformationMethod2.java @@ -15,7 +15,7 @@ */ package android.text.method; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * TransformationMethod2 extends the TransformationMethod interface diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java index 313567acb51f..d766186c13b0 100644 --- a/core/java/android/text/method/WordIterator.java +++ b/core/java/android/text/method/WordIterator.java @@ -17,7 +17,7 @@ package android.text.method; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.icu.lang.UCharacter; import android.icu.lang.UProperty; import android.icu.text.BreakIterator; diff --git a/core/java/android/text/style/BulletSpan.java b/core/java/android/text/style/BulletSpan.java index 9b1dfbfc95e6..ad617889cd56 100644 --- a/core/java/android/text/style/BulletSpan.java +++ b/core/java/android/text/style/BulletSpan.java @@ -21,7 +21,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Build; diff --git a/core/java/android/text/style/DynamicDrawableSpan.java b/core/java/android/text/style/DynamicDrawableSpan.java index 1a508a1f6c6d..f37e4238a1c6 100644 --- a/core/java/android/text/style/DynamicDrawableSpan.java +++ b/core/java/android/text/style/DynamicDrawableSpan.java @@ -22,7 +22,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java index bfb2873b5112..b23c2b7da6ac 100644 --- a/core/java/android/text/style/EasyEditSpan.java +++ b/core/java/android/text/style/EasyEditSpan.java @@ -17,8 +17,8 @@ package android.text.style; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.text.ParcelableSpan; import android.text.TextUtils; diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java index 98f58bef5932..ec55aebfb0ac 100644 --- a/core/java/android/text/style/ImageSpan.java +++ b/core/java/android/text/style/ImageSpan.java @@ -19,7 +19,7 @@ package android.text.style; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; diff --git a/core/java/android/text/style/SpellCheckSpan.java b/core/java/android/text/style/SpellCheckSpan.java index 6ffde38a3b75..e8ec3c6fb55c 100644 --- a/core/java/android/text/style/SpellCheckSpan.java +++ b/core/java/android/text/style/SpellCheckSpan.java @@ -16,7 +16,7 @@ package android.text.style; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.text.ParcelableSpan; import android.text.TextUtils; diff --git a/core/java/android/text/style/SuggestionRangeSpan.java b/core/java/android/text/style/SuggestionRangeSpan.java index d958ddebaf5a..2b04a7ac2ab8 100644 --- a/core/java/android/text/style/SuggestionRangeSpan.java +++ b/core/java/android/text/style/SuggestionRangeSpan.java @@ -16,7 +16,7 @@ package android.text.style; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.text.ParcelableSpan; import android.text.TextPaint; diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java index c000ae3f6b2a..be01bfb94f21 100644 --- a/core/java/android/text/style/SuggestionSpan.java +++ b/core/java/android/text/style/SuggestionSpan.java @@ -19,7 +19,7 @@ package android.text.style; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index df54209bc043..6931a323f195 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -19,7 +19,7 @@ package android.text.util; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java new file mode 100644 index 000000000000..e5bbdf4b6eea --- /dev/null +++ b/core/java/android/timezone/CountryTimeZones.java @@ -0,0 +1,266 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.icu.util.TimeZone; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Information about a country's time zones. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class CountryTimeZones { + + /** + * A mapping to a time zone ID with some associated metadata. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class TimeZoneMapping { + + @NonNull + private libcore.timezone.CountryTimeZones.TimeZoneMapping mDelegate; + + TimeZoneMapping(libcore.timezone.CountryTimeZones.TimeZoneMapping delegate) { + this.mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the ID for this mapping. See also {@link #getTimeZone()} which handles when the + * ID is unrecognized. + */ + @NonNull + public String getTimeZoneId() { + return mDelegate.timeZoneId; + } + + /** + * Returns a {@link TimeZone} object for this mapping, or {@code null} if the ID is + * unrecognized. + */ + @Nullable + public TimeZone getTimeZone() { + return mDelegate.getTimeZone(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TimeZoneMapping that = (TimeZoneMapping) o; + return this.mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return this.mDelegate.hashCode(); + } + + @Override + public String toString() { + return mDelegate.toString(); + } + } + + /** + * The result of lookup up a time zone using offset information (and possibly more). + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class OffsetResult { + + private final TimeZone mTimeZone; + private final boolean mIsOnlyMatch; + + /** Creates an instance with the supplied information. */ + public OffsetResult(@NonNull TimeZone timeZone, boolean isOnlyMatch) { + mTimeZone = Objects.requireNonNull(timeZone); + mIsOnlyMatch = isOnlyMatch; + } + + /** + * Returns a time zone that matches the supplied criteria. + */ + @NonNull + public TimeZone getTimeZone() { + return mTimeZone; + } + + /** + * Returns {@code true} if there is only one matching time zone for the supplied criteria. + */ + public boolean isOnlyMatch() { + return mIsOnlyMatch; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + OffsetResult that = (OffsetResult) o; + return mIsOnlyMatch == that.mIsOnlyMatch + && mTimeZone.getID().equals(that.mTimeZone.getID()); + } + + @Override + public int hashCode() { + return Objects.hash(mTimeZone, mIsOnlyMatch); + } + + @Override + public String toString() { + return "OffsetResult{" + + "mTimeZone=" + mTimeZone + + ", mIsOnlyMatch=" + mIsOnlyMatch + + '}'; + } + } + + @NonNull + private final libcore.timezone.CountryTimeZones mDelegate; + + CountryTimeZones(libcore.timezone.CountryTimeZones delegate) { + mDelegate = delegate; + } + + /** + * Returns true if the ISO code for the country is a match for the one specified. + */ + public boolean isForCountryCode(@NonNull String countryIso) { + return mDelegate.isForCountryCode(countryIso); + } + + /** + * Returns the default time zone ID for the country. Can return {@code null} in cases when no + * data is available or the time zone ID was not recognized. + */ + @Nullable + public String getDefaultTimeZoneId() { + return mDelegate.getDefaultTimeZoneId(); + } + + /** + * Returns the default time zone for the country. Can return {@code null} in cases when no data + * is available or the time zone ID was not recognized. + */ + @Nullable + public TimeZone getDefaultTimeZone() { + return mDelegate.getDefaultTimeZone(); + } + + /** + * Qualifier for a country's default time zone. {@code true} indicates whether the default + * would be a good choice <em>generally</em> when there's no other information available. + */ + public boolean isDefaultTimeZoneBoosted() { + return mDelegate.getDefaultTimeZoneBoost(); + } + + /** + * Returns true if the country has at least one zone that is the same as UTC at the given time. + */ + public boolean hasUtcZone(long whenMillis) { + return mDelegate.hasUtcZone(whenMillis); + } + + /** + * Returns a time zone for the country, if there is one, that matches the desired properties. If + * there are multiple matches and the {@code bias} is one of them then it is returned, otherwise + * an arbitrary match is returned based on the {@link #getEffectiveTimeZoneMappingsAt(long)} + * ordering. + * + * @param totalOffsetMillis the offset from UTC at {@code whenMillis} + * @param isDst the Daylight Savings Time state at {@code whenMillis}. {@code true} means DST, + * {@code false} means not DST, {@code null} means unknown + * @param dstOffsetMillis the part of {@code totalOffsetMillis} contributed by DST, only used if + * {@code isDst} is {@code true}. The value can be {@code null} if the DST offset is + * unknown + * @param whenMillis the UTC time to match against + * @param bias the time zone to prefer, can be {@code null} + */ + @Nullable + public OffsetResult lookupByOffsetWithBias(int totalOffsetMillis, @Nullable Boolean isDst, + @SuppressLint("AutoBoxing") @Nullable Integer dstOffsetMillis, long whenMillis, + @Nullable TimeZone bias) { + libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult = + mDelegate.lookupByOffsetWithBias( + totalOffsetMillis, isDst, dstOffsetMillis, whenMillis, bias); + return delegateOffsetResult == null ? null : + new OffsetResult(delegateOffsetResult.mTimeZone, delegateOffsetResult.mOneMatch); + } + + /** + * Returns an immutable, ordered list of time zone mappings for the country in an undefined but + * "priority" order, filtered so that only "effective" time zone IDs are returned. An + * "effective" time zone is one that differs from another time zone used in the country after + * {@code whenMillis}. The list can be empty if there were no zones configured or the configured + * zone IDs were not recognized. + */ + @NonNull + public List<TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long whenMillis) { + List<libcore.timezone.CountryTimeZones.TimeZoneMapping> delegateList = + mDelegate.getEffectiveTimeZoneMappingsAt(whenMillis); + + List<TimeZoneMapping> toReturn = new ArrayList<>(delegateList.size()); + for (libcore.timezone.CountryTimeZones.TimeZoneMapping delegateMapping : delegateList) { + toReturn.add(new TimeZoneMapping(delegateMapping)); + } + return Collections.unmodifiableList(toReturn); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CountryTimeZones that = (CountryTimeZones) o; + return mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return Objects.hash(mDelegate); + } + + @Override + public String toString() { + return mDelegate.toString(); + } +} diff --git a/core/java/android/timezone/TelephonyLookup.java b/core/java/android/timezone/TelephonyLookup.java new file mode 100644 index 000000000000..eebccf4aa577 --- /dev/null +++ b/core/java/android/timezone/TelephonyLookup.java @@ -0,0 +1,70 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; + +import com.android.internal.annotations.GuardedBy; + +import java.util.Objects; + +/** + * A class that can find time zone-related information about telephony networks. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public class TelephonyLookup { + + private static Object sLock = new Object(); + @GuardedBy("sLock") + private static TelephonyLookup sInstance; + + /** + * Obtains an instance for use when resolving telephony time zone information. + */ + @NonNull + public static TelephonyLookup getInstance() { + synchronized (sLock) { + if (sInstance == null) { + sInstance = new TelephonyLookup(libcore.timezone.TelephonyLookup.getInstance()); + } + return sInstance; + } + } + + @NonNull + private final libcore.timezone.TelephonyLookup mDelegate; + + private TelephonyLookup(@NonNull libcore.timezone.TelephonyLookup delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns an object capable of querying telephony network information. This method can return + * {@code null} in the event of an error while reading the underlying data files. + */ + @Nullable + public TelephonyNetworkFinder getTelephonyNetworkFinder() { + libcore.timezone.TelephonyNetworkFinder telephonyNetworkFinderDelegate = + mDelegate.getTelephonyNetworkFinder(); + return telephonyNetworkFinderDelegate != null + ? new TelephonyNetworkFinder(telephonyNetworkFinderDelegate) : null; + } +} diff --git a/core/java/android/timezone/TelephonyNetwork.java b/core/java/android/timezone/TelephonyNetwork.java new file mode 100644 index 000000000000..ae39fbddfa1c --- /dev/null +++ b/core/java/android/timezone/TelephonyNetwork.java @@ -0,0 +1,86 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import java.util.Objects; + +/** + * Information about a telephony network. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public class TelephonyNetwork { + + @NonNull + private final libcore.timezone.TelephonyNetwork mDelegate; + + TelephonyNetwork(@NonNull libcore.timezone.TelephonyNetwork delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the Mobile Country Code of the network. + */ + @NonNull + public String getMcc() { + return mDelegate.getMcc(); + } + + /** + * Returns the Mobile Network Code of the network. + */ + @NonNull + public String getMnc() { + return mDelegate.getMnc(); + } + + /** + * Returns the country in which the network operates as an ISO 3166 alpha-2 (lower case). + */ + @NonNull + public String getCountryIsoCode() { + return mDelegate.getCountryIsoCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TelephonyNetwork that = (TelephonyNetwork) o; + return mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return Objects.hash(mDelegate); + } + + @Override + public String toString() { + return "TelephonyNetwork{" + + "mDelegate=" + mDelegate + + '}'; + } +} diff --git a/core/java/android/timezone/TelephonyNetworkFinder.java b/core/java/android/timezone/TelephonyNetworkFinder.java new file mode 100644 index 000000000000..079d0882f191 --- /dev/null +++ b/core/java/android/timezone/TelephonyNetworkFinder.java @@ -0,0 +1,55 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; + +import java.util.Objects; + +/** + * A class that can find telephony network information loaded via {@link TelephonyLookup}. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public class TelephonyNetworkFinder { + + @NonNull + private final libcore.timezone.TelephonyNetworkFinder mDelegate; + + TelephonyNetworkFinder(libcore.timezone.TelephonyNetworkFinder delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns information held about a specific MCC + MNC combination. It is expected for this + * method to return {@code null}. Only known, unusual networks will typically have information + * returned, e.g. if they operate in countries other than the one suggested by their MCC. + */ + @Nullable + public TelephonyNetwork findNetworkByMccMnc(@NonNull String mcc, @NonNull String mnc) { + Objects.requireNonNull(mcc); + Objects.requireNonNull(mnc); + + libcore.timezone.TelephonyNetwork telephonyNetworkDelegate = + mDelegate.findNetworkByMccMnc(mcc, mnc); + return telephonyNetworkDelegate != null + ? new TelephonyNetwork(telephonyNetworkDelegate) : null; + } +} diff --git a/core/java/android/timezone/TimeZoneFinder.java b/core/java/android/timezone/TimeZoneFinder.java new file mode 100644 index 000000000000..9327b001a9c8 --- /dev/null +++ b/core/java/android/timezone/TimeZoneFinder.java @@ -0,0 +1,78 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; + +import com.android.internal.annotations.GuardedBy; + +import java.util.Objects; + +/** + * A class that can be used to find time zones using information like country and offset. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class TimeZoneFinder { + + private static Object sLock = new Object(); + @GuardedBy("sLock") + private static TimeZoneFinder sInstance; + + /** + * Obtains the singleton instance. + */ + @NonNull + public static TimeZoneFinder getInstance() { + synchronized (sLock) { + if (sInstance == null) { + sInstance = new TimeZoneFinder(libcore.timezone.TimeZoneFinder.getInstance()); + } + } + return sInstance; + } + + @NonNull + private final libcore.timezone.TimeZoneFinder mDelegate; + + private TimeZoneFinder(@NonNull libcore.timezone.TimeZoneFinder delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the IANA rules version associated with the data. If there is no version information + * or there is a problem reading the file then {@code null} is returned. + */ + @Nullable + public String getIanaVersion() { + return mDelegate.getIanaVersion(); + } + + /** + * Returns a {@link CountryTimeZones} object associated with the specified country code. + * Caching is handled as needed. If the country code is not recognized or there is an error + * during lookup this method can return null. + */ + @Nullable + public CountryTimeZones lookupCountryTimeZones(@NonNull String countryIso) { + libcore.timezone.CountryTimeZones delegate = mDelegate.lookupCountryTimeZones(countryIso); + return delegate == null ? null : new CountryTimeZones(delegate); + } +} diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java new file mode 100644 index 000000000000..aba7c4c15903 --- /dev/null +++ b/core/java/android/timezone/TzDataSetVersion.java @@ -0,0 +1,154 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.IOException; +import java.util.Objects; + +/** + * Version information associated with the set of time zone data on a device. + * + * <p>Time Zone Data Sets have a major ({@link #getFormatMajorVersion()}) and minor + * ({@link #currentFormatMinorVersion()}) version number: + * <ul> + * <li>Major version numbers are mutually incompatible. e.g. v2 is not compatible with a v1 or a + * v3 device.</li> + * <li>Minor version numbers are backwards compatible. e.g. a v2.2 data set will work + * on a v2.1 device but not a v2.3 device. The minor version is reset to 1 when the major version + * is incremented.</li> + * </ul> + * + * <p>Data sets contain time zone rules and other data associated wtih a tzdb release + * ({@link #getRulesVersion()}) and an additional Android-specific revision number + * ({@link #getRevision()}). + * + * <p>See platform/system/timezone/README.android for more information. + * @hide + */ +@VisibleForTesting +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class TzDataSetVersion { + + /** + * Returns the major tz data format version supported by this device. + */ + public static int currentFormatMajorVersion() { + return libcore.timezone.TzDataSetVersion.currentFormatMajorVersion(); + } + + /** + * Returns the minor tz data format version supported by this device. + */ + public static int currentFormatMinorVersion() { + return libcore.timezone.TzDataSetVersion.currentFormatMinorVersion(); + } + + /** + * Returns true if the version information provided would be compatible with this device, i.e. + * with the current system image, and set of active modules. + */ + public static boolean isCompatibleWithThisDevice(TzDataSetVersion tzDataSetVersion) { + return libcore.timezone.TzDataSetVersion.isCompatibleWithThisDevice( + tzDataSetVersion.mDelegate); + } + + /** + * Reads the current Android time zone data set version file. + */ + @NonNull + public static TzDataSetVersion read() throws IOException, TzDataSetException { + try { + return new TzDataSetVersion( + libcore.timezone.TzDataSetVersion.readTimeZoneModuleVersion()); + } catch (libcore.timezone.TzDataSetVersion.TzDataSetException e) { + throw new TzDataSetException(e.getMessage(), e); + } + } + + /** + * A checked exception used in connection with time zone data sets. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static class TzDataSetException extends Exception { + + /** Creates an instance with a message. */ + public TzDataSetException(String message) { + super(message); + } + + /** Creates an instance with a message and a cause. */ + public TzDataSetException(String message, Throwable cause) { + super(message, cause); + } + } + + @NonNull + private final libcore.timezone.TzDataSetVersion mDelegate; + + private TzDataSetVersion(@NonNull libcore.timezone.TzDataSetVersion delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** Returns the major version number. See {@link TzDataSetVersion}. */ + public int getFormatMajorVersion() { + return mDelegate.formatMajorVersion; + } + + /** Returns the minor version number. See {@link TzDataSetVersion}. */ + public int getFormatMinorVersion() { + return mDelegate.formatMinorVersion; + } + + /** Returns the tzdb version string. See {@link TzDataSetVersion}. */ + @NonNull + public String getRulesVersion() { + return mDelegate.rulesVersion; + } + + /** Returns the Android revision. See {@link TzDataSetVersion}. */ + public int getRevision() { + return mDelegate.revision; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TzDataSetVersion that = (TzDataSetVersion) o; + return mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return Objects.hash(mDelegate); + } + + @Override + public String toString() { + return mDelegate.toString(); + } +} diff --git a/core/java/android/timezone/ZoneInfoDb.java b/core/java/android/timezone/ZoneInfoDb.java new file mode 100644 index 000000000000..eb191e8e3272 --- /dev/null +++ b/core/java/android/timezone/ZoneInfoDb.java @@ -0,0 +1,66 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import com.android.internal.annotations.GuardedBy; + +import java.util.Objects; + +/** + * Android's internal factory for java.util.TimeZone objects. Provides access to core library time + * zone metadata not available via {@link java.util.TimeZone}. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class ZoneInfoDb { + + private static Object sLock = new Object(); + @GuardedBy("sLock") + private static ZoneInfoDb sInstance; + + /** + * Obtains the singleton instance. + */ + @NonNull + public static ZoneInfoDb getInstance() { + synchronized (sLock) { + if (sInstance == null) { + sInstance = new ZoneInfoDb(libcore.timezone.ZoneInfoDB.getInstance()); + } + } + return sInstance; + } + + @NonNull + private final libcore.timezone.ZoneInfoDB mDelegate; + + private ZoneInfoDb(libcore.timezone.ZoneInfoDB delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the tzdb version in use. + */ + @NonNull + public String getVersion() { + return mDelegate.getVersion(); + } +} diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java index de182daaeb53..59a05ac3c493 100644 --- a/core/java/android/transition/ChangeBounds.java +++ b/core/java/android/transition/ChangeBounds.java @@ -22,7 +22,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.RectEvaluator; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; diff --git a/core/java/android/transition/Scene.java b/core/java/android/transition/Scene.java index 8d4db54ab7b1..52a97e31e081 100644 --- a/core/java/android/transition/Scene.java +++ b/core/java/android/transition/Scene.java @@ -18,7 +18,7 @@ package android.transition; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.util.SparseArray; diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 0feab4d027a9..e5115846013f 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -20,7 +20,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TimeInterpolator; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Path; diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index 0e5252e21a64..1b0612e87202 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -17,7 +17,7 @@ package android.transition; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.ArrayMap; import android.util.Log; diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index d899dde9ef59..5643d5ad24b2 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.ArrayUtils; diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java index d6a35e1b96fc..489d579365ba 100644 --- a/core/java/android/util/ArraySet.java +++ b/core/java/android/util/ArraySet.java @@ -18,7 +18,7 @@ package android.util; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import libcore.util.EmptyArray; diff --git a/core/java/android/util/Base64.java b/core/java/android/util/Base64.java index ecc0c9cc9de3..92abd7c15f5f 100644 --- a/core/java/android/util/Base64.java +++ b/core/java/android/util/Base64.java @@ -16,7 +16,8 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.UnsupportedEncodingException; /** diff --git a/core/java/android/util/Base64OutputStream.java b/core/java/android/util/Base64OutputStream.java index 230a3a58d5b5..48fadeb2a5af 100644 --- a/core/java/android/util/Base64OutputStream.java +++ b/core/java/android/util/Base64OutputStream.java @@ -16,7 +16,8 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java index 55d114b224f2..1b4905ad06b6 100644 --- a/core/java/android/util/DebugUtils.java +++ b/core/java/android/util/DebugUtils.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import java.io.PrintWriter; diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 7c7223c04b59..4c08b596ee1f 100755 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.SystemProperties; diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java index 65d825a71d81..c9dc05b5aeb5 100644 --- a/core/java/android/util/EventLog.java +++ b/core/java/android/util/EventLog.java @@ -17,7 +17,7 @@ package android.util; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.BufferedReader; import java.io.FileReader; diff --git a/core/java/android/util/IconDrawableFactory.java b/core/java/android/util/IconDrawableFactory.java index d90b65e22171..be10d941bf5e 100644 --- a/core/java/android/util/IconDrawableFactory.java +++ b/core/java/android/util/IconDrawableFactory.java @@ -15,8 +15,8 @@ */ package android.util; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java index 0203430134c4..63fe61ff0926 100644 --- a/core/java/android/util/LocalLog.java +++ b/core/java/android/util/LocalLog.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.SystemClock; import java.io.FileDescriptor; diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index 507790313bc2..3077b7987034 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -19,7 +19,7 @@ package android.util; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.DeadSystemException; import com.android.internal.os.RuntimeInit; @@ -387,6 +387,25 @@ public final class Log { public static native int println_native(int bufID, int priority, String tag, String msg); /** + * Send a log message to the "radio" log buffer, which can be dumped with + * {@code adb logcat -b radio}. + * + * <p>Only the telephony mainline module should use it. + * + * <p>Note ART will protect {@code MODULE_LIBRARIES} system APIs from regular app code. + * + * @param priority Log priority. + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param message The message you would like logged. + * @hide + */ + public static int logToRadioBuffer(@Level int priority, @Nullable String tag, + @Nullable String message) { + return println_native(LOG_ID_RADIO, priority, tag, message); + } + + /** * Return the maximum payload the log daemon accepts without truncation. * @return LOGGER_ENTRY_MAX_PAYLOAD. */ diff --git a/core/java/android/util/LogWriter.java b/core/java/android/util/LogWriter.java index b062ace05700..a674ae166d63 100644 --- a/core/java/android/util/LogWriter.java +++ b/core/java/android/util/LogWriter.java @@ -16,7 +16,8 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.Writer; /** @hide */ diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java index 6f4aa5211dea..93bcd6b8d4a1 100644 --- a/core/java/android/util/LongArray.java +++ b/core/java/android/util/LongArray.java @@ -17,7 +17,7 @@ package android.util; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java index 7b7eea09e884..75f41350fa55 100644 --- a/core/java/android/util/LongSparseLongArray.java +++ b/core/java/android/util/LongSparseLongArray.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java index f04e7cbc9e8f..d35c82bfa158 100644 --- a/core/java/android/util/LruCache.java +++ b/core/java/android/util/LruCache.java @@ -16,7 +16,8 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.LinkedHashMap; import java.util.Map; diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java index 0eeef70a79a6..971e16185815 100644 --- a/core/java/android/util/MathUtils.java +++ b/core/java/android/util/MathUtils.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; /** diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java index da566c934ef7..0892c94d5bec 100644 --- a/core/java/android/util/NtpTrustedTime.java +++ b/core/java/android/util/NtpTrustedTime.java @@ -16,7 +16,9 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; @@ -28,151 +30,267 @@ import android.os.SystemClock; import android.provider.Settings; import android.text.TextUtils; +import com.android.internal.annotations.GuardedBy; + +import java.util.Objects; +import java.util.function.Supplier; + /** - * {@link TrustedTime} that connects with a remote NTP server as its trusted - * time source. + * A singleton that connects with a remote NTP server as its trusted time source. This class + * is thread-safe. The {@link #forceRefresh()} method is synchronous, i.e. it may occupy the + * current thread while performing an NTP request. All other threads calling {@link #forceRefresh()} + * will block during that request. * * @hide */ public class NtpTrustedTime implements TrustedTime { + + /** + * The result of a successful NTP query. + * + * @hide + */ + public static class TimeResult { + private final long mTimeMillis; + private final long mElapsedRealtimeMillis; + private final long mCertaintyMillis; + + public TimeResult(long timeMillis, long elapsedRealtimeMillis, long certaintyMillis) { + mTimeMillis = timeMillis; + mElapsedRealtimeMillis = elapsedRealtimeMillis; + mCertaintyMillis = certaintyMillis; + } + + public long getTimeMillis() { + return mTimeMillis; + } + + public long getElapsedRealtimeMillis() { + return mElapsedRealtimeMillis; + } + + public long getCertaintyMillis() { + return mCertaintyMillis; + } + + /** Calculates and returns the current time accounting for the age of this result. */ + public long currentTimeMillis() { + return mTimeMillis + getAgeMillis(); + } + + /** Calculates and returns the age of this result. */ + public long getAgeMillis() { + return SystemClock.elapsedRealtime() - mElapsedRealtimeMillis; + } + + @Override + public String toString() { + return "TimeResult{" + + "mTimeMillis=" + mTimeMillis + + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + + ", mCertaintyMillis=" + mCertaintyMillis + + '}'; + } + } + private static final String TAG = "NtpTrustedTime"; private static final boolean LOGD = false; private static NtpTrustedTime sSingleton; - private static Context sContext; - private final String mServer; - private final long mTimeout; + @NonNull + private final Context mContext; + + /** + * A supplier that returns the ConnectivityManager. The Supplier can return null if + * ConnectivityService isn't running yet. + */ + private final Supplier<ConnectivityManager> mConnectivityManagerSupplier = + new Supplier<ConnectivityManager>() { + private ConnectivityManager mConnectivityManager; - private ConnectivityManager mCM; + @Nullable + @Override + public synchronized ConnectivityManager get() { + // We can't do this at initialization time: ConnectivityService might not be running + // yet. + if (mConnectivityManager == null) { + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + } + return mConnectivityManager; + } + }; - private boolean mHasCache; - private long mCachedNtpTime; - private long mCachedNtpElapsedRealtime; - private long mCachedNtpCertainty; + // Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during + // forceRefresh(). + private volatile TimeResult mTimeResult; - private NtpTrustedTime(String server, long timeout) { - if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server); - mServer = server; - mTimeout = timeout; + private NtpTrustedTime(Context context) { + mContext = Objects.requireNonNull(context); } @UnsupportedAppUsage public static synchronized NtpTrustedTime getInstance(Context context) { if (sSingleton == null) { - final Resources res = context.getResources(); - final ContentResolver resolver = context.getContentResolver(); - - final String defaultServer = res.getString( - com.android.internal.R.string.config_ntpServer); - final long defaultTimeout = res.getInteger( - com.android.internal.R.integer.config_ntpTimeout); - - final String secureServer = Settings.Global.getString( - resolver, Settings.Global.NTP_SERVER); - final long timeout = Settings.Global.getLong( - resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout); - - final String server = secureServer != null ? secureServer : defaultServer; - sSingleton = new NtpTrustedTime(server, timeout); - sContext = context; + Context appContext = context.getApplicationContext(); + sSingleton = new NtpTrustedTime(appContext); } - return sSingleton; } - @Override @UnsupportedAppUsage public boolean forceRefresh() { - // We can't do this at initialization time: ConnectivityService might not be running yet. synchronized (this) { - if (mCM == null) { - mCM = sContext.getSystemService(ConnectivityManager.class); + NtpConnectionInfo connectionInfo = getNtpConnectionInfo(); + if (connectionInfo == null) { + // missing server config, so no trusted time available + if (LOGD) Log.d(TAG, "forceRefresh: invalid server config"); + return false; } - } - - final Network network = mCM == null ? null : mCM.getActiveNetwork(); - return forceRefresh(network); - } - public boolean forceRefresh(Network network) { - if (TextUtils.isEmpty(mServer)) { - // missing server, so no trusted time available - return false; - } - - // We can't do this at initialization time: ConnectivityService might not be running yet. - synchronized (this) { - if (mCM == null) { - mCM = sContext.getSystemService(ConnectivityManager.class); + ConnectivityManager connectivityManager = mConnectivityManagerSupplier.get(); + if (connectivityManager == null) { + if (LOGD) Log.d(TAG, "forceRefresh: no ConnectivityManager"); + return false; + } + final Network network = connectivityManager.getActiveNetwork(); + final NetworkInfo ni = connectivityManager.getNetworkInfo(network); + if (ni == null || !ni.isConnected()) { + if (LOGD) Log.d(TAG, "forceRefresh: no connectivity"); + return false; } - } - - final NetworkInfo ni = mCM == null ? null : mCM.getNetworkInfo(network); - if (ni == null || !ni.isConnected()) { - if (LOGD) Log.d(TAG, "forceRefresh: no connectivity"); - return false; - } - - if (LOGD) Log.d(TAG, "forceRefresh() from cache miss"); - final SntpClient client = new SntpClient(); - if (client.requestTime(mServer, (int) mTimeout, network)) { - mHasCache = true; - mCachedNtpTime = client.getNtpTime(); - mCachedNtpElapsedRealtime = client.getNtpTimeReference(); - mCachedNtpCertainty = client.getRoundTripTime() / 2; - return true; - } else { - return false; + if (LOGD) Log.d(TAG, "forceRefresh() from cache miss"); + final SntpClient client = new SntpClient(); + final String serverName = connectionInfo.getServer(); + final int timeoutMillis = connectionInfo.getTimeoutMillis(); + if (client.requestTime(serverName, timeoutMillis, network)) { + long ntpCertainty = client.getRoundTripTime() / 2; + mTimeResult = new TimeResult( + client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty); + return true; + } else { + return false; + } } } - @Override + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @UnsupportedAppUsage public boolean hasCache() { - return mHasCache; + return mTimeResult != null; } + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @Override public long getCacheAge() { - if (mHasCache) { - return SystemClock.elapsedRealtime() - mCachedNtpElapsedRealtime; + TimeResult timeResult = mTimeResult; + if (timeResult != null) { + return SystemClock.elapsedRealtime() - timeResult.getElapsedRealtimeMillis(); } else { return Long.MAX_VALUE; } } - @Override - public long getCacheCertainty() { - if (mHasCache) { - return mCachedNtpCertainty; - } else { - return Long.MAX_VALUE; - } - } - - @Override + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @UnsupportedAppUsage public long currentTimeMillis() { - if (!mHasCache) { + TimeResult timeResult = mTimeResult; + if (timeResult == null) { throw new IllegalStateException("Missing authoritative time source"); } if (LOGD) Log.d(TAG, "currentTimeMillis() cache hit"); // current time is age after the last ntp cache; callers who - // want fresh values will hit makeAuthoritative() first. - return mCachedNtpTime + getCacheAge(); + // want fresh values will hit forceRefresh() first. + return timeResult.currentTimeMillis(); } + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @UnsupportedAppUsage public long getCachedNtpTime() { if (LOGD) Log.d(TAG, "getCachedNtpTime() cache hit"); - return mCachedNtpTime; + TimeResult timeResult = mTimeResult; + return timeResult == null ? 0 : timeResult.getTimeMillis(); } + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @UnsupportedAppUsage public long getCachedNtpTimeReference() { - return mCachedNtpElapsedRealtime; + TimeResult timeResult = mTimeResult; + return timeResult == null ? 0 : timeResult.getElapsedRealtimeMillis(); + } + + /** + * Returns an object containing the latest NTP information available. Can return {@code null} if + * no information is available. + */ + @Nullable + public TimeResult getCachedTimeResult() { + return mTimeResult; + } + + private static class NtpConnectionInfo { + + @NonNull private final String mServer; + private final int mTimeoutMillis; + + NtpConnectionInfo(@NonNull String server, int timeoutMillis) { + mServer = Objects.requireNonNull(server); + mTimeoutMillis = timeoutMillis; + } + + @NonNull + public String getServer() { + return mServer; + } + + int getTimeoutMillis() { + return mTimeoutMillis; + } + } + + @GuardedBy("this") + private NtpConnectionInfo getNtpConnectionInfo() { + final ContentResolver resolver = mContext.getContentResolver(); + + final Resources res = mContext.getResources(); + final String defaultServer = res.getString( + com.android.internal.R.string.config_ntpServer); + final int defaultTimeoutMillis = res.getInteger( + com.android.internal.R.integer.config_ntpTimeout); + + final String secureServer = Settings.Global.getString( + resolver, Settings.Global.NTP_SERVER); + final int timeoutMillis = Settings.Global.getInt( + resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis); + + final String server = secureServer != null ? secureServer : defaultServer; + return TextUtils.isEmpty(server) ? null : new NtpConnectionInfo(server, timeoutMillis); } } diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java index 5342d5dfc81d..1e5ec0b1c5c3 100644 --- a/core/java/android/util/PathParser.java +++ b/core/java/android/util/PathParser.java @@ -14,7 +14,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Path; import dalvik.annotation.optimization.FastNative; diff --git a/core/java/android/util/Pools.java b/core/java/android/util/Pools.java index e242fe5cfca3..7ae32441ef60 100644 --- a/core/java/android/util/Pools.java +++ b/core/java/android/util/Pools.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Helper class for crating pools of objects. An example use looks like this: diff --git a/core/java/android/util/Rational.java b/core/java/android/util/Rational.java index 39e8b14689da..593000002cf7 100644 --- a/core/java/android/util/Rational.java +++ b/core/java/android/util/Rational.java @@ -15,9 +15,10 @@ */ package android.util; -import static com.android.internal.util.Preconditions.*; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.compat.annotation.UnsupportedAppUsage; -import android.annotation.UnsupportedAppUsage; import java.io.IOException; import java.io.InvalidObjectException; diff --git a/core/java/android/util/RecurrenceRule.java b/core/java/android/util/RecurrenceRule.java index 9c60228b4f87..a570e5e00b1c 100644 --- a/core/java/android/util/RecurrenceRule.java +++ b/core/java/android/util/RecurrenceRule.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/util/Singleton.java b/core/java/android/util/Singleton.java index 15c6b5b5d7f8..92646b47cef2 100644 --- a/core/java/android/util/Singleton.java +++ b/core/java/android/util/Singleton.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Singleton helper class for lazily initialization. diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java index a85120f67f8d..2c8bbbfcf8de 100644 --- a/core/java/android/util/Slog.java +++ b/core/java/android/util/Slog.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; /** diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 0a15db227823..3a0d1f5a6cc8 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java index d6e0e53a210d..846df397aa6d 100644 --- a/core/java/android/util/SparseBooleanArray.java +++ b/core/java/android/util/SparseBooleanArray.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index 1ca1717828fa..d4f6685e4347 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -16,7 +16,7 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java new file mode 100644 index 000000000000..c7659457bdf9 --- /dev/null +++ b/core/java/android/util/StatsEvent.java @@ -0,0 +1,829 @@ +/* + * 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.util; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.SystemClock; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +/** + * StatsEvent builds and stores the buffer sent over the statsd socket. + * This class defines and encapsulates the socket protocol. + * + * <p>Usage:</p> + * <pre> + * // Pushed event + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeBoolean(false) + * .writeString("annotated String field") + * .addBooleanAnnotation(annotationId, true) + * .usePooledBuffer() + * .build(); + * StatsLog.write(statsEvent); + * + * // Pulled event + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeBoolean(false) + * .writeString("annotated String field") + * .addBooleanAnnotation(annotationId, true) + * .build(); + * </pre> + * @hide + **/ +public final class StatsEvent { + // Type Ids. + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_INT = 0x00; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_LONG = 0x01; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_STRING = 0x02; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_LIST = 0x03; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_FLOAT = 0x04; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_BOOLEAN = 0x05; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_BYTE_ARRAY = 0x06; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_OBJECT = 0x07; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_KEY_VALUE_PAIRS = 0x08; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_ATTRIBUTION_CHAIN = 0x09; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_ERRORS = 0x0F; + + // Error flags. + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_NO_TIMESTAMP = 0x1; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_NO_ATOM_ID = 0x2; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_OVERFLOW = 0x4; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_ATTRIBUTION_CHAIN_TOO_LONG = 0x8; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_TOO_MANY_KEY_VALUE_PAIRS = 0x10; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD = 0x20; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_INVALID_ANNOTATION_ID = 0x40; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_ANNOTATION_ID_TOO_LARGE = 0x80; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_TOO_MANY_ANNOTATIONS = 0x100; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_TOO_MANY_FIELDS = 0x200; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL = 0x1000; + + // Size limits. + + /** + * @hide + **/ + @VisibleForTesting + public static final int MAX_ANNOTATION_COUNT = 15; + + /** + * @hide + **/ + @VisibleForTesting + public static final int MAX_ATTRIBUTION_NODES = 127; + + /** + * @hide + **/ + @VisibleForTesting + public static final int MAX_NUM_ELEMENTS = 127; + + /** + * @hide + **/ + @VisibleForTesting + public static final int MAX_KEY_VALUE_PAIRS = 127; + + private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068; + + // Max payload size is 4 bytes less as 4 bytes are reserved for statsEventTag. + // See android_util_StatsLog.cpp. + private static final int MAX_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4; + + private final int mAtomId; + private final byte[] mPayload; + private Buffer mBuffer; + private final int mNumBytes; + + private StatsEvent(final int atomId, @Nullable final Buffer buffer, + @NonNull final byte[] payload, final int numBytes) { + mAtomId = atomId; + mBuffer = buffer; + mPayload = payload; + mNumBytes = numBytes; + } + + /** + * Returns a new StatsEvent.Builder for building StatsEvent object. + **/ + @NonNull + public static StatsEvent.Builder newBuilder() { + return new StatsEvent.Builder(Buffer.obtain()); + } + + /** + * Get the atom Id of the atom encoded in this StatsEvent object. + * + * @hide + **/ + public int getAtomId() { + return mAtomId; + } + + /** + * Get the byte array that contains the encoded payload that can be sent to statsd. + * + * @hide + **/ + @NonNull + public byte[] getBytes() { + return mPayload; + } + + /** + * Get the number of bytes used to encode the StatsEvent payload. + * + * @hide + **/ + public int getNumBytes() { + return mNumBytes; + } + + /** + * Recycle resources used by this StatsEvent object. + * No actions should be taken on this StatsEvent after release() is called. + **/ + public void release() { + if (mBuffer != null) { + mBuffer.release(); + mBuffer = null; + } + } + + /** + * Builder for constructing a StatsEvent object. + * + * <p>This class defines and encapsulates the socket encoding for the buffer. + * The write methods must be called in the same order as the order of fields in the + * atom definition.</p> + * + * <p>setAtomId() can be called anytime before build().</p> + * + * <p>Example:</p> + * <pre> + * // Atom definition. + * message MyAtom { + * optional int32 field1 = 1; + * optional int64 field2 = 2; + * optional string field3 = 3 [(annotation1) = true]; + * } + * + * // StatsEvent construction for pushed event. + * StatsEvent.newBuilder() + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeInt(3) // field1 + * .writeLong(8L) // field2 + * .writeString("foo") // field 3 + * .addBooleanAnnotation(annotation1Id, true) + * .usePooledBuffer() + * .build(); + * + * // StatsEvent construction for pulled event. + * StatsEvent.newBuilder() + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeInt(3) // field1 + * .writeLong(8L) // field2 + * .writeString("foo") // field 3 + * .addBooleanAnnotation(annotation1Id, true) + * .build(); + * </pre> + **/ + public static final class Builder { + // Fixed positions. + private static final int POS_NUM_ELEMENTS = 1; + private static final int POS_TIMESTAMP_NS = POS_NUM_ELEMENTS + Byte.BYTES; + private static final int POS_ATOM_ID = POS_TIMESTAMP_NS + Byte.BYTES + Long.BYTES; + + private final Buffer mBuffer; + private long mTimestampNs; + private int mAtomId; + private byte mCurrentAnnotationCount; + private int mPos; + private int mPosLastField; + private byte mLastType; + private int mNumElements; + private int mErrorMask; + private boolean mUsePooledBuffer = false; + + private Builder(final Buffer buffer) { + mBuffer = buffer; + mCurrentAnnotationCount = 0; + mAtomId = 0; + mTimestampNs = SystemClock.elapsedRealtimeNanos(); + mNumElements = 0; + + // Set mPos to 0 for writing TYPE_OBJECT at 0th position. + mPos = 0; + writeTypeId(TYPE_OBJECT); + + // Set mPos to after atom id's location in the buffer. + // First 2 elements in the buffer are event timestamp followed by the atom id. + mPos = POS_ATOM_ID + Byte.BYTES + Integer.BYTES; + mPosLastField = 0; + mLastType = 0; + } + + /** + * Sets the atom id for this StatsEvent. + **/ + @NonNull + public Builder setAtomId(final int atomId) { + mAtomId = atomId; + return this; + } + + /** + * Sets the timestamp in nanos for this StatsEvent. + **/ + @VisibleForTesting + @NonNull + public Builder setTimestampNs(final long timestampNs) { + mTimestampNs = timestampNs; + return this; + } + + /** + * Write a boolean field to this StatsEvent. + **/ + @NonNull + public Builder writeBoolean(final boolean value) { + // Write boolean typeId byte followed by boolean byte representation. + writeTypeId(TYPE_BOOLEAN); + mPos += mBuffer.putBoolean(mPos, value); + mNumElements++; + return this; + } + + /** + * Write an integer field to this StatsEvent. + **/ + @NonNull + public Builder writeInt(final int value) { + // Write integer typeId byte followed by 4-byte representation of value. + writeTypeId(TYPE_INT); + mPos += mBuffer.putInt(mPos, value); + mNumElements++; + return this; + } + + /** + * Write a long field to this StatsEvent. + **/ + @NonNull + public Builder writeLong(final long value) { + // Write long typeId byte followed by 8-byte representation of value. + writeTypeId(TYPE_LONG); + mPos += mBuffer.putLong(mPos, value); + mNumElements++; + return this; + } + + /** + * Write a float field to this StatsEvent. + **/ + @NonNull + public Builder writeFloat(final float value) { + // Write float typeId byte followed by 4-byte representation of value. + writeTypeId(TYPE_FLOAT); + mPos += mBuffer.putFloat(mPos, value); + mNumElements++; + return this; + } + + /** + * Write a String field to this StatsEvent. + **/ + @NonNull + public Builder writeString(@NonNull final String value) { + // Write String typeId byte, followed by 4-byte representation of number of bytes + // in the UTF-8 encoding, followed by the actual UTF-8 byte encoding of value. + final byte[] valueBytes = stringToBytes(value); + writeByteArray(valueBytes, TYPE_STRING); + return this; + } + + /** + * Write a byte array field to this StatsEvent. + **/ + @NonNull + public Builder writeByteArray(@NonNull final byte[] value) { + // Write byte array typeId byte, followed by 4-byte representation of number of bytes + // in value, followed by the actual byte array. + writeByteArray(value, TYPE_BYTE_ARRAY); + return this; + } + + private void writeByteArray(@NonNull final byte[] value, final byte typeId) { + writeTypeId(typeId); + final int numBytes = value.length; + mPos += mBuffer.putInt(mPos, numBytes); + mPos += mBuffer.putByteArray(mPos, value); + mNumElements++; + } + + /** + * Write an attribution chain field to this StatsEvent. + * + * The sizes of uids and tags must be equal. The AttributionNode at position i is + * made up of uids[i] and tags[i]. + * + * @param uids array of uids in the attribution nodes. + * @param tags array of tags in the attribution nodes. + **/ + @NonNull + public Builder writeAttributionChain( + @NonNull final int[] uids, @NonNull final String[] tags) { + final byte numUids = (byte) uids.length; + final byte numTags = (byte) tags.length; + + if (numUids != numTags) { + mErrorMask |= ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL; + } else if (numUids > MAX_ATTRIBUTION_NODES) { + mErrorMask |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG; + } else { + // Write attribution chain typeId byte, followed by 1-byte representation of + // number of attribution nodes, followed by encoding of each attribution node. + writeTypeId(TYPE_ATTRIBUTION_CHAIN); + mPos += mBuffer.putByte(mPos, numUids); + for (int i = 0; i < numUids; i++) { + // Each uid is encoded as 4-byte representation of its int value. + mPos += mBuffer.putInt(mPos, uids[i]); + + // Each tag is encoded as 4-byte representation of number of bytes in its + // UTF-8 encoding, followed by the actual UTF-8 bytes. + final byte[] tagBytes = stringToBytes(tags[i]); + mPos += mBuffer.putInt(mPos, tagBytes.length); + mPos += mBuffer.putByteArray(mPos, tagBytes); + } + mNumElements++; + } + return this; + } + + /** + * Write KeyValuePairsAtom entries to this StatsEvent. + * + * @param intMap Integer key-value pairs. + * @param longMap Long key-value pairs. + * @param stringMap String key-value pairs. + * @param floatMap Float key-value pairs. + **/ + @NonNull + public Builder writeKeyValuePairs( + @NonNull final SparseIntArray intMap, + @NonNull final SparseLongArray longMap, + @NonNull final SparseArray<String> stringMap, + @NonNull final SparseArray<Float> floatMap) { + final int intMapSize = intMap.size(); + final int longMapSize = longMap.size(); + final int stringMapSize = stringMap.size(); + final int floatMapSize = floatMap.size(); + final int totalCount = intMapSize + longMapSize + stringMapSize + floatMapSize; + + if (totalCount > MAX_KEY_VALUE_PAIRS) { + mErrorMask |= ERROR_TOO_MANY_KEY_VALUE_PAIRS; + } else { + writeTypeId(TYPE_KEY_VALUE_PAIRS); + mPos += mBuffer.putByte(mPos, (byte) totalCount); + + for (int i = 0; i < intMapSize; i++) { + final int key = intMap.keyAt(i); + final int value = intMap.valueAt(i); + mPos += mBuffer.putInt(mPos, key); + writeTypeId(TYPE_INT); + mPos += mBuffer.putInt(mPos, value); + } + + for (int i = 0; i < longMapSize; i++) { + final int key = longMap.keyAt(i); + final long value = longMap.valueAt(i); + mPos += mBuffer.putInt(mPos, key); + writeTypeId(TYPE_LONG); + mPos += mBuffer.putLong(mPos, value); + } + + for (int i = 0; i < stringMapSize; i++) { + final int key = stringMap.keyAt(i); + final String value = stringMap.valueAt(i); + mPos += mBuffer.putInt(mPos, key); + writeTypeId(TYPE_STRING); + final byte[] valueBytes = stringToBytes(value); + mPos += mBuffer.putInt(mPos, valueBytes.length); + mPos += mBuffer.putByteArray(mPos, valueBytes); + } + + for (int i = 0; i < floatMapSize; i++) { + final int key = floatMap.keyAt(i); + final float value = floatMap.valueAt(i); + mPos += mBuffer.putInt(mPos, key); + writeTypeId(TYPE_FLOAT); + mPos += mBuffer.putFloat(mPos, value); + } + + mNumElements++; + } + + return this; + } + + /** + * Write a boolean annotation for the last field written. + **/ + @NonNull + public Builder addBooleanAnnotation( + final byte annotationId, final boolean value) { + // Ensure there's a field written to annotate. + if (0 == mPosLastField) { + mErrorMask |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD; + } else if (mCurrentAnnotationCount >= MAX_ANNOTATION_COUNT) { + mErrorMask |= ERROR_TOO_MANY_ANNOTATIONS; + } else { + mPos += mBuffer.putByte(mPos, annotationId); + mPos += mBuffer.putByte(mPos, TYPE_BOOLEAN); + mPos += mBuffer.putBoolean(mPos, value); + mCurrentAnnotationCount++; + writeAnnotationCount(); + } + return this; + } + + /** + * Write an integer annotation for the last field written. + **/ + @NonNull + public Builder addIntAnnotation(final byte annotationId, final int value) { + if (0 == mPosLastField) { + mErrorMask |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD; + } else if (mCurrentAnnotationCount >= MAX_ANNOTATION_COUNT) { + mErrorMask |= ERROR_TOO_MANY_ANNOTATIONS; + } else { + mPos += mBuffer.putByte(mPos, annotationId); + mPos += mBuffer.putByte(mPos, TYPE_INT); + mPos += mBuffer.putInt(mPos, value); + mCurrentAnnotationCount++; + writeAnnotationCount(); + } + return this; + } + + /** + * Indicates to reuse Buffer's byte array as the underlying payload in StatsEvent. + * This should be called for pushed events to reduce memory allocations and garbage + * collections. + **/ + @NonNull + public Builder usePooledBuffer() { + mUsePooledBuffer = true; + return this; + } + + /** + * Builds a StatsEvent object with values entered in this Builder. + **/ + @NonNull + public StatsEvent build() { + if (0L == mTimestampNs) { + mErrorMask |= ERROR_NO_TIMESTAMP; + } + if (0 == mAtomId) { + mErrorMask |= ERROR_NO_ATOM_ID; + } + if (mBuffer.hasOverflowed()) { + mErrorMask |= ERROR_OVERFLOW; + } + if (mNumElements > MAX_NUM_ELEMENTS) { + mErrorMask |= ERROR_TOO_MANY_FIELDS; + } + + int size = mPos; + mPos = POS_TIMESTAMP_NS; + writeLong(mTimestampNs); + writeInt(mAtomId); + if (0 == mErrorMask) { + mBuffer.putByte(POS_NUM_ELEMENTS, (byte) mNumElements); + } else { + mPos += mBuffer.putByte(mPos, TYPE_ERRORS); + mPos += mBuffer.putInt(mPos, mErrorMask); + mBuffer.putByte(POS_NUM_ELEMENTS, (byte) 3); + size = mPos; + } + + if (mUsePooledBuffer) { + return new StatsEvent(mAtomId, mBuffer, mBuffer.getBytes(), size); + } else { + // Create a copy of the buffer with the required number of bytes. + final byte[] payload = new byte[size]; + System.arraycopy(mBuffer.getBytes(), 0, payload, 0, size); + + // Return Buffer instance to the pool. + mBuffer.release(); + + return new StatsEvent(mAtomId, null, payload, size); + } + } + + private void writeTypeId(final byte typeId) { + mPosLastField = mPos; + mLastType = typeId; + mCurrentAnnotationCount = 0; + final byte encodedId = (byte) (typeId & 0x0F); + mPos += mBuffer.putByte(mPos, encodedId); + } + + private void writeAnnotationCount() { + // Use first 4 bits for annotation count and last 4 bits for typeId. + final byte encodedId = (byte) ((mCurrentAnnotationCount << 4) | (mLastType & 0x0F)); + mBuffer.putByte(mPosLastField, encodedId); + } + + @NonNull + private static byte[] stringToBytes(@Nullable final String value) { + return (null == value ? "" : value).getBytes(UTF_8); + } + } + + private static final class Buffer { + private static Object sLock = new Object(); + + @GuardedBy("sLock") + private static Buffer sPool; + + private final byte[] mBytes = new byte[MAX_PAYLOAD_SIZE]; + private boolean mOverflow = false; + + @NonNull + private static Buffer obtain() { + final Buffer buffer; + synchronized (sLock) { + buffer = null == sPool ? new Buffer() : sPool; + sPool = null; + } + buffer.reset(); + return buffer; + } + + private Buffer() { + } + + @NonNull + private byte[] getBytes() { + return mBytes; + } + + private void release() { + synchronized (sLock) { + if (null == sPool) { + sPool = this; + } + } + } + + private void reset() { + mOverflow = false; + } + + private boolean hasOverflowed() { + return mOverflow; + } + + /** + * Checks for available space in the byte array. + * + * @param index starting position in the buffer to start the check. + * @param numBytes number of bytes to check from index. + * @return true if space is available, false otherwise. + **/ + private boolean hasEnoughSpace(final int index, final int numBytes) { + final boolean result = index + numBytes < MAX_PAYLOAD_SIZE; + if (!result) { + mOverflow = true; + } + return result; + } + + /** + * Writes a byte into the buffer. + * + * @param index position in the buffer where the byte is written. + * @param value the byte to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putByte(final int index, final byte value) { + if (hasEnoughSpace(index, Byte.BYTES)) { + mBytes[index] = (byte) (value); + return Byte.BYTES; + } + return 0; + } + + /** + * Writes a boolean into the buffer. + * + * @param index position in the buffer where the boolean is written. + * @param value the boolean to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putBoolean(final int index, final boolean value) { + return putByte(index, (byte) (value ? 1 : 0)); + } + + /** + * Writes an integer into the buffer. + * + * @param index position in the buffer where the integer is written. + * @param value the integer to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putInt(final int index, final int value) { + if (hasEnoughSpace(index, Integer.BYTES)) { + // Use little endian byte order. + mBytes[index] = (byte) (value); + mBytes[index + 1] = (byte) (value >> 8); + mBytes[index + 2] = (byte) (value >> 16); + mBytes[index + 3] = (byte) (value >> 24); + return Integer.BYTES; + } + return 0; + } + + /** + * Writes a long into the buffer. + * + * @param index position in the buffer where the long is written. + * @param value the long to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putLong(final int index, final long value) { + if (hasEnoughSpace(index, Long.BYTES)) { + // Use little endian byte order. + mBytes[index] = (byte) (value); + mBytes[index + 1] = (byte) (value >> 8); + mBytes[index + 2] = (byte) (value >> 16); + mBytes[index + 3] = (byte) (value >> 24); + mBytes[index + 4] = (byte) (value >> 32); + mBytes[index + 5] = (byte) (value >> 40); + mBytes[index + 6] = (byte) (value >> 48); + mBytes[index + 7] = (byte) (value >> 56); + return Long.BYTES; + } + return 0; + } + + /** + * Writes a float into the buffer. + * + * @param index position in the buffer where the float is written. + * @param value the float to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putFloat(final int index, final float value) { + return putInt(index, Float.floatToIntBits(value)); + } + + /** + * Copies a byte array into the buffer. + * + * @param index position in the buffer where the byte array is copied. + * @param value the byte array to copy. + * @return number of bytes written to buffer from this write operation. + **/ + private int putByteArray(final int index, @NonNull final byte[] value) { + final int numBytes = value.length; + if (hasEnoughSpace(index, numBytes)) { + System.arraycopy(value, 0, mBytes, index, numBytes); + return numBytes; + } + return 0; + } + } +} diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index ae9966b7b934..23fd4f2f61d3 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -244,6 +244,19 @@ public final class StatsLog extends StatsLogInternal { */ private static native void writeImpl(@NonNull byte[] buffer, int size, int atomId); + /** + * Write an event to stats log using the raw format encapsulated in StatsEvent. + * After writing to stats log, release() is called on the StatsEvent object. + * No further action should be taken on the StatsEvent object following this call. + * + * @param statsEvent The StatsEvent object containing the encoded buffer of data to write. + * @hide + */ + public static void write(@NonNull final StatsEvent statsEvent) { + writeImpl(statsEvent.getBytes(), statsEvent.getNumBytes(), statsEvent.getAtomId()); + statsEvent.release(); + } + private static void enforceDumpCallingPermission(Context context) { context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission."); } diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 74cff205dabc..dbd3f69e214e 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -19,7 +19,7 @@ package android.util; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.SystemClock; @@ -88,7 +88,7 @@ public class TimeUtils { * * <p>The list returned may be different from other on-device sources like * {@link android.icu.util.TimeZone#getRegion(String)} as it can be curated to avoid - * contentious mappings. + * contentious or obsolete mappings. * * @param countryCode the ISO 3166-1 alpha-2 code for the country as can be obtained using * {@link java.util.Locale#getCountry()} diff --git a/core/java/android/util/TrustedTime.java b/core/java/android/util/TrustedTime.java index c78665d06e75..f41fe85fa8bb 100644 --- a/core/java/android/util/TrustedTime.java +++ b/core/java/android/util/TrustedTime.java @@ -16,46 +16,52 @@ package android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Interface that provides trusted time information, possibly coming from an NTP - * server. Implementations may cache answers until {@link #forceRefresh()}. + * server. * * @hide + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ public interface TrustedTime { /** * Force update with an external trusted time source, returning {@code true} * when successful. + * + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ + @Deprecated @UnsupportedAppUsage public boolean forceRefresh(); /** * Check if this instance has cached a response from a trusted time source. + * + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ + @Deprecated @UnsupportedAppUsage - public boolean hasCache(); + boolean hasCache(); /** * Return time since last trusted time source contact, or * {@link Long#MAX_VALUE} if never contacted. + * + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ + @Deprecated @UnsupportedAppUsage public long getCacheAge(); /** - * Return certainty of cached trusted time in milliseconds, or - * {@link Long#MAX_VALUE} if never contacted. Smaller values are more - * precise. - */ - public long getCacheCertainty(); - - /** * Return current time similar to {@link System#currentTimeMillis()}, * possibly using a cached authoritative time source. + * + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ + @Deprecated @UnsupportedAppUsage - public long currentTimeMillis(); + long currentTimeMillis(); } diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java index 32fe16fcb2b1..d83b355d81a6 100644 --- a/core/java/android/util/XmlPullAttributes.java +++ b/core/java/android/util/XmlPullAttributes.java @@ -16,13 +16,12 @@ package android.util; -import org.xmlpull.v1.XmlPullParser; - -import android.annotation.UnsupportedAppUsage; -import android.util.AttributeSet; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlPullParser; + /** * Provides an implementation of AttributeSet on top of an XmlPullParser. */ diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java index 6efcfbfd05f8..7b24ba997307 100644 --- a/core/java/android/util/proto/ProtoOutputStream.java +++ b/core/java/android/util/proto/ProtoOutputStream.java @@ -16,7 +16,8 @@ package android.util.proto; -import android.annotation.TestApi; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.util.Log; import java.io.FileDescriptor; @@ -28,19 +29,23 @@ import java.io.UnsupportedEncodingException; /** * Class to write to a protobuf stream. * - * Each write method takes an ID code from the protoc generated classes - * and the value to write. To make a nested object, call #start - * and then #end when you are done. + * <p> + * This API is not as convenient or type safe as the standard protobuf + * classes. If possible, the best recommended library is to use protobuf lite. + * However, in environements (such as the Android platform itself), a + * more memory efficient version is necessary. * - * The ID codes have type information embedded into them, so if you call - * the incorrect function you will get an IllegalArgumentException. + * <p>Each write method takes an ID code from the protoc generated classes + * and the value to write. To make a nested object, call {@link #start(long)} + * and then {@link #end(long)} when you are done. * - * To retrieve the encoded protobuf stream, call getBytes(). + * <p>The ID codes have type information embedded into them, so if you call + * the incorrect function you will get an {@link IllegalArgumentException}. + * + * <p>To retrieve the encoded protobuf stream, call {@link #getBytes()}. * - * TODO: Add a constructor that takes an OutputStream and write to that * stream as the top-level objects are finished. * - * @hide */ /* IMPLEMENTATION NOTES @@ -99,7 +104,6 @@ import java.io.UnsupportedEncodingException; * correctly matched pairs of #start and #end calls, and issue * errors if they are not matched. */ -@TestApi public final class ProtoOutputStream extends ProtoStream { /** * @hide @@ -124,7 +128,9 @@ public final class ProtoOutputStream extends ProtoStream { /** * An ID given to objects and returned in the token from startObject * and stored in the buffer until endObject is called, where the two - * are checked. Starts at -1 and becomes more negative, so the values + * are checked. + * + * <p>Starts at -1 and becomes more negative, so the values * aren't likely to alias with the size it will be overwritten with, * which tend to be small, and we will be more likely to catch when * the caller of endObject uses a stale token that they didn't intend @@ -133,8 +139,9 @@ public final class ProtoOutputStream extends ProtoStream { private int mNextObjectId = -1; /** - * The object token we are expecting in endObject. If another call to - * startObject happens, this is written to that location, which gives + * The object token we are expecting in endObject. + * + * <p>If another call to startObject happens, this is written to that location, which gives * us a stack, stored in the space for the as-yet unused size fields. */ private long mExpectedObjectToken; @@ -151,39 +158,45 @@ public final class ProtoOutputStream extends ProtoStream { private boolean mCompacted; /** - * Construct a ProtoOutputStream with the default chunk size. + * Construct a {@link ProtoOutputStream} with the default chunk size. + * + * <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result. */ public ProtoOutputStream() { this(0); } /** - * Construct a ProtoOutputStream with the given chunk size. + * Construct a {@link ProtoOutputStream with the given chunk size. + * + * <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result. */ public ProtoOutputStream(int chunkSize) { mBuffer = new EncodedBuffer(chunkSize); } /** - * Construct a ProtoOutputStream that sits on top of an OutputStream. - * @more - * The {@link #flush() flush()} method must be called when done writing - * to flush any remanining data, althought data *may* be written at intermediate + * Construct a {@link ProtoOutputStream} that sits on top of an {@link OutputStream}. + * + * <p>The {@link #flush()} method must be called when done writing + * to flush any remaining data, although data *may* be written at intermediate * points within the writing as well. */ - public ProtoOutputStream(OutputStream stream) { + public ProtoOutputStream(@NonNull OutputStream stream) { this(); mStream = stream; } /** - * Construct a ProtoOutputStream that sits on top of a FileDescriptor. - * @more - * The {@link #flush() flush()} method must be called when done writing - * to flush any remanining data, althought data *may* be written at intermediate + * Construct a {@link ProtoOutputStream} that sits on top of a {@link FileDescriptor}. + * + * <p>The {@link #flush()} method must be called when done writing + * to flush any remaining data, although data *may* be written at intermediate * points within the writing as well. + * + * @hide */ - public ProtoOutputStream(FileDescriptor fd) { + public ProtoOutputStream(@NonNull FileDescriptor fd) { this(new FileOutputStream(fd)); } @@ -202,7 +215,7 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a value for the given fieldId. * - * Will automatically convert for the following field types, and + * <p>Will automatically convert for the following field types, and * throw an exception for others: double, float, int32, int64, uint32, uint64, * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum. * @@ -337,7 +350,7 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a value for the given fieldId. * - * Will automatically convert for the following field types, and + * <p>Will automatically convert for the following field types, and * throw an exception for others: double, float, int32, int64, uint32, uint64, * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum. * @@ -472,7 +485,7 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a value for the given fieldId. * - * Will automatically convert for the following field types, and + * <p>Will automatically convert for the following field types, and * throw an exception for others: double, float, int32, int64, uint32, uint64, * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum. * @@ -607,7 +620,7 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a value for the given fieldId. * - * Will automatically convert for the following field types, and + * <p>Will automatically convert for the following field types, and * throw an exception for others: double, float, int32, int64, uint32, uint64, * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum. * @@ -742,7 +755,7 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a boolean value for the given fieldId. * - * If the field is not a bool field, an exception will be thrown. + * <p>If the field is not a bool field, an {@link IllegalStateException} will be thrown. * * @param fieldId The field identifier constant from the generated class. * @param val The value. @@ -771,12 +784,12 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a string value for the given fieldId. * - * If the field is not a string field, an exception will be thrown. + * <p>If the field is not a string field, an exception will be thrown. * * @param fieldId The field identifier constant from the generated class. * @param val The value. */ - public void write(long fieldId, String val) { + public void write(long fieldId, @Nullable String val) { assertNotCompacted(); final int id = (int)fieldId; @@ -800,12 +813,12 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a byte[] value for the given fieldId. * - * If the field is not a bytes or object field, an exception will be thrown. + * <p>If the field is not a bytes or object field, an exception will be thrown. * * @param fieldId The field identifier constant from the generated class. * @param val The value. */ - public void write(long fieldId, byte[] val) { + public void write(long fieldId, @Nullable byte[] val) { assertNotCompacted(); final int id = (int)fieldId; @@ -836,6 +849,9 @@ public final class ProtoOutputStream extends ProtoStream { /** * Start a sub object. + * + * @param fieldId The field identifier constant from the generated class. + * @return The token to call {@link #end(long)} with. */ public long start(long fieldId) { assertNotCompacted(); @@ -855,6 +871,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * End the object started by start() that returned token. + * + * @param token The token returned from {@link #start(long)} */ public void end(long token) { endObjectImpl(token, getRepeatedFromToken(token)); @@ -870,7 +888,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "double" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, double)} instead. + * @hide */ @Deprecated public void writeDouble(long fieldId, double val) { @@ -890,7 +909,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "double" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, double)} instead. + * @hide */ @Deprecated public void writeRepeatedDouble(long fieldId, double val) { @@ -908,10 +928,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "double" type field values. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, double)} instead. + * @hide */ @Deprecated - public void writePackedDouble(long fieldId, double[] val) { + public void writePackedDouble(long fieldId, @Nullable double[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_DOUBLE); @@ -934,7 +955,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "float" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, float)} instead. + * @hide */ @Deprecated public void writeFloat(long fieldId, float val) { @@ -954,7 +976,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "float" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, float)} instead. + * @hide */ @Deprecated public void writeRepeatedFloat(long fieldId, float val) { @@ -972,10 +995,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "float" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, float)} instead. + * @hide */ @Deprecated - public void writePackedFloat(long fieldId, float[] val) { + public void writePackedFloat(long fieldId, @Nullable float[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FLOAT); @@ -999,7 +1023,7 @@ public final class ProtoOutputStream extends ProtoStream { /** * Writes a java int as an usigned varint. * - * The unadorned int32 type in protobuf is unfortunate because it + * <p>The unadorned int32 type in protobuf is unfortunate because it * is stored in memory as a signed value, but encodes as unsigned * varints, which are formally always longs. So here, we encode * negative values as 64 bits, which will get the sign-extension, @@ -1017,11 +1041,12 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "int32" type field value. * - * Note that these are stored in memory as signed values and written as unsigned + * <p>Note that these are stored in memory as signed values and written as unsigned * varints, which if negative, are 10 bytes long. If you know the data is likely * to be negative, use "sint32". * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeInt32(long fieldId, int val) { @@ -1041,11 +1066,12 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "int32" type field value. * - * Note that these are stored in memory as signed values and written as unsigned + * <p>Note that these are stored in memory as signed values and written as unsigned * varints, which if negative, are 10 bytes long. If you know the data is likely * to be negative, use "sint32". * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeRepeatedInt32(long fieldId, int val) { @@ -1063,14 +1089,15 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "int32" type field value. * - * Note that these are stored in memory as signed values and written as unsigned + * <p>Note that these are stored in memory as signed values and written as unsigned * varints, which if negative, are 10 bytes long. If you know the data is likely * to be negative, use "sint32". * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated - public void writePackedInt32(long fieldId, int[] val) { + public void writePackedInt32(long fieldId, @Nullable int[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT32); @@ -1099,7 +1126,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "int64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeInt64(long fieldId, long val) { @@ -1119,7 +1147,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "int64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeRepeatedInt64(long fieldId, long val) { @@ -1137,10 +1166,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "int64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated - public void writePackedInt64(long fieldId, long[] val) { + public void writePackedInt64(long fieldId, @Nullable long[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT64); @@ -1168,7 +1198,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "uint32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeUInt32(long fieldId, int val) { @@ -1188,7 +1219,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "uint32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeRepeatedUInt32(long fieldId, int val) { @@ -1206,10 +1238,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "uint32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated - public void writePackedUInt32(long fieldId, int[] val) { + public void writePackedUInt32(long fieldId, @Nullable int[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT32); @@ -1237,7 +1270,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "uint64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeUInt64(long fieldId, long val) { @@ -1257,7 +1291,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "uint64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeRepeatedUInt64(long fieldId, long val) { @@ -1275,10 +1310,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "uint64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated - public void writePackedUInt64(long fieldId, long[] val) { + public void writePackedUInt64(long fieldId, @Nullable long[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT64); @@ -1306,7 +1342,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "sint32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeSInt32(long fieldId, int val) { @@ -1326,7 +1363,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "sint32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeRepeatedSInt32(long fieldId, int val) { @@ -1344,10 +1382,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "sint32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated - public void writePackedSInt32(long fieldId, int[] val) { + public void writePackedSInt32(long fieldId, @Nullable int[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT32); @@ -1375,7 +1414,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "sint64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeSInt64(long fieldId, long val) { @@ -1395,7 +1435,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "sint64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeRepeatedSInt64(long fieldId, long val) { @@ -1413,10 +1454,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "sint64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated - public void writePackedSInt64(long fieldId, long[] val) { + public void writePackedSInt64(long fieldId, @Nullable long[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT64); @@ -1443,7 +1485,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "fixed32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeFixed32(long fieldId, int val) { @@ -1463,7 +1506,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "fixed32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeRepeatedFixed32(long fieldId, int val) { @@ -1481,10 +1525,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "fixed32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated - public void writePackedFixed32(long fieldId, int[] val) { + public void writePackedFixed32(long fieldId, @Nullable int[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED32); @@ -1507,7 +1552,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "fixed64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeFixed64(long fieldId, long val) { @@ -1527,7 +1573,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "fixed64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeRepeatedFixed64(long fieldId, long val) { @@ -1545,10 +1592,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "fixed64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated - public void writePackedFixed64(long fieldId, long[] val) { + public void writePackedFixed64(long fieldId, @Nullable long[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED64); @@ -1570,7 +1618,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "sfixed32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeSFixed32(long fieldId, int val) { @@ -1590,7 +1639,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "sfixed32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeRepeatedSFixed32(long fieldId, int val) { @@ -1608,10 +1658,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "sfixed32" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated - public void writePackedSFixed32(long fieldId, int[] val) { + public void writePackedSFixed32(long fieldId, @Nullable int[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED32); @@ -1634,7 +1685,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "sfixed64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeSFixed64(long fieldId, long val) { @@ -1654,7 +1706,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "sfixed64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated public void writeRepeatedSFixed64(long fieldId, long val) { @@ -1672,10 +1725,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "sfixed64" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, long)} instead. + * @hide */ @Deprecated - public void writePackedSFixed64(long fieldId, long[] val) { + public void writePackedSFixed64(long fieldId, @Nullable long[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED64); @@ -1698,7 +1752,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "bool" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, boolean)} instead. + * @hide */ @Deprecated public void writeBool(long fieldId, boolean val) { @@ -1719,7 +1774,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "bool" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, boolean)} instead. + * @hide */ @Deprecated public void writeRepeatedBool(long fieldId, boolean val) { @@ -1737,10 +1793,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto "bool" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, boolean)} instead. + * @hide */ @Deprecated - public void writePackedBool(long fieldId, boolean[] val) { + public void writePackedBool(long fieldId, @Nullable boolean[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_BOOL); @@ -1767,10 +1824,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "string" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, String)} instead. + * @hide */ @Deprecated - public void writeString(long fieldId, String val) { + public void writeString(long fieldId, @Nullable String val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_STRING); @@ -1786,10 +1844,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "string" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, String)} instead. + * @hide */ @Deprecated - public void writeRepeatedString(long fieldId, String val) { + public void writeRepeatedString(long fieldId, @Nullable String val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_STRING); @@ -1828,10 +1887,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto "bytes" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, byte[])} instead. + * @hide */ @Deprecated - public void writeBytes(long fieldId, byte[] val) { + public void writeBytes(long fieldId, @Nullable byte[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES); @@ -1848,10 +1908,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto "bytes" type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, byte[])} instead. + * @hide */ @Deprecated - public void writeRepeatedBytes(long fieldId, byte[] val) { + public void writeRepeatedBytes(long fieldId, @Nullable byte[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BYTES); @@ -1874,7 +1935,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single proto enum type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeEnum(long fieldId, int val) { @@ -1894,7 +1956,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a single repeated proto enum type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated public void writeRepeatedEnum(long fieldId, int val) { @@ -1912,10 +1975,11 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write a list of packed proto enum type field value. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, int)} instead. + * @hide */ @Deprecated - public void writePackedEnum(long fieldId, int[] val) { + public void writePackedEnum(long fieldId, @Nullable int[] val) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_ENUM); @@ -1940,7 +2004,8 @@ public final class ProtoOutputStream extends ProtoStream { * Returns a token which should be passed to endObject. Calls to endObject must be * nested properly. * - * @deprecated Use #start() instead. + * @deprecated Use {@link #start(long)} instead. + * @hide */ @Deprecated public long startObject(long fieldId) { @@ -1953,7 +2018,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * End a child object. Pass in the token from the correspoinding startObject call. * - * @deprecated Use #end() instead. + * @deprecated Use {@link #end(long)} instead. + * @hide */ @Deprecated public void endObject(long token) { @@ -1968,7 +2034,8 @@ public final class ProtoOutputStream extends ProtoStream { * Returns a token which should be passed to endObject. Calls to endObject must be * nested properly. * - * @deprecated Use #start() instead. + * @deprecated Use {@link #start(long)} instead. + * @hide */ @Deprecated public long startRepeatedObject(long fieldId) { @@ -1981,7 +2048,8 @@ public final class ProtoOutputStream extends ProtoStream { /** * End a child object. Pass in the token from the correspoinding startRepeatedObject call. * - * @deprecated Use #end() instead. + * @deprecated Use {@link #end(long)} instead. + * @hide */ @Deprecated public void endRepeatedObject(long token) { @@ -2064,12 +2132,13 @@ public final class ProtoOutputStream extends ProtoStream { } /** - * Write an object that has already been flattend. + * Write an object that has already been flattened. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, byte[])} instead. + * @hide */ @Deprecated - public void writeObject(long fieldId, byte[] value) { + public void writeObject(long fieldId, @Nullable byte[] value) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE); @@ -2084,12 +2153,13 @@ public final class ProtoOutputStream extends ProtoStream { } /** - * Write an object that has already been flattend. + * Write an object that has already been flattened. * - * @deprecated Use #write instead. + * @deprecated Use {@link #write(long, byte[])} instead. + * @hide */ @Deprecated - public void writeRepeatedObject(long fieldId, byte[] value) { + public void writeRepeatedObject(long fieldId, @Nullable byte[] value) { assertNotCompacted(); final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE); @@ -2115,11 +2185,11 @@ public final class ProtoOutputStream extends ProtoStream { } /** - * Validates that the fieldId providied is of the type and count from expectedType. + * Validates that the fieldId provided is of the type and count from expectedType. * - * The type must match exactly to pass this check. + * <p>The type must match exactly to pass this check. * - * The count must match according to this truth table to pass the check: + * <p>The count must match according to this truth table to pass the check: * * expectedFlags * UNKNOWN SINGLE REPEATED PACKED @@ -2129,7 +2199,7 @@ public final class ProtoOutputStream extends ProtoStream { * REPEATED x false true false * PACKED x false true true * - * @throws IllegalArgumentException if it is not. + * @throws {@link IllegalArgumentException} if it is not. * * @return The raw ID of that field. */ @@ -2201,7 +2271,7 @@ public final class ProtoOutputStream extends ProtoStream { } /** - * Write a field tage to the stream. + * Write a field tag to the stream. */ public void writeTag(int id, int wireType) { mBuffer.writeRawVarint32((id << FIELD_ID_SHIFT) | wireType); @@ -2239,10 +2309,10 @@ public final class ProtoOutputStream extends ProtoStream { * Finish the encoding of the data, and return a byte[] with * the protobuf formatted data. * - * After this call, do not call any of the write* functions. The + * <p>After this call, do not call any of the write* functions. The * behavior is undefined. */ - public byte[] getBytes() { + public @NonNull byte[] getBytes() { compactIfNecessary(); return mBuffer.getBytes(mBuffer.getReadableSize()); @@ -2289,7 +2359,7 @@ public final class ProtoOutputStream extends ProtoStream { } /** - * First compaction pass. Iterate through the data, and fill in the + * First compaction pass. Iterate through the data, and fill in the * nested object sizes so the next pass can compact them. */ private int editEncodedSize(int rawSize) { @@ -2416,10 +2486,10 @@ public final class ProtoOutputStream extends ProtoStream { /** * Write remaining data to the output stream. If there is no output stream, * this function does nothing. Any currently open objects (i.e. ones that - * have not had endObject called for them will not be written). Whether this + * have not had {@link #end(long)} called for them will not be written). Whether this * writes objects that are closed if there are remaining open objects is * undefined (current implementation does not write it, future ones will). - * For now, can either call getBytes() or flush(), but not both. + * For now, can either call {@link #getBytes()} or {@link #flush()}, but not both. */ public void flush() { if (mStream == null) { @@ -2457,7 +2527,7 @@ public final class ProtoOutputStream extends ProtoStream { /** * Dump debugging data about the buffers with the given log tag. */ - public void dump(String tag) { + public void dump(@NonNull String tag) { Log.d(tag, mBuffer.getDebugString()); mBuffer.dumpBuffers(tag); } diff --git a/core/java/android/util/proto/ProtoStream.java b/core/java/android/util/proto/ProtoStream.java index 9e2e95a5923d..4969d8a7fbe7 100644 --- a/core/java/android/util/proto/ProtoStream.java +++ b/core/java/android/util/proto/ProtoStream.java @@ -16,28 +16,104 @@ package android.util.proto; -import android.annotation.TestApi; +import android.annotation.NonNull; +import android.annotation.Nullable; /** - * Abstract base class for both protobuf streams. + * Base utility class for protobuf streams. * - * Contains a set of useful constants and methods used by both - * ProtoOutputStream and ProtoInputStream + * Contains a set of constants and methods used in generated code for + * {@link ProtoOutputStream}. * * @hide */ -@TestApi -public abstract class ProtoStream { +public class ProtoStream { + /** + * Number of bits to shift the field number to form a tag. + * + * <pre> + * // Reading a field number from a tag. + * int fieldNumber = tag >>> FIELD_ID_SHIFT; + * + * // Building a tag from a field number and a wire type. + * int tag = (fieldNumber << FIELD_ID_SHIFT) | wireType; + * </pre> + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final int FIELD_ID_SHIFT = 3; + + /** + * Mask to select the wire type from a tag. + * + * <pre> + * // Reading a wire type from a tag. + * int wireType = tag & WIRE_TYPE_MASK; + * + * // Building a tag from a field number and a wire type. + * int tag = (fieldNumber << FIELD_ID_SHIFT) | wireType; + * </pre> + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final int WIRE_TYPE_MASK = (1 << FIELD_ID_SHIFT) - 1; + + /** + * Mask to select the field id from a tag. + * @hide (not used by anything, and not actually useful, because you also want + * to shift when you mask the field id). + */ public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK; + /** + * Varint wire type code. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final int WIRE_TYPE_VARINT = 0; + + /** + * Fixed64 wire type code. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final int WIRE_TYPE_FIXED64 = 1; + + /** + * Length delimited wire type code. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final int WIRE_TYPE_LENGTH_DELIMITED = 2; + + /** + * Start group wire type code. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final int WIRE_TYPE_START_GROUP = 3; + + /** + * End group wire type code. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final int WIRE_TYPE_END_GROUP = 4; + + /** + * Fixed32 wire type code. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final int WIRE_TYPE_FIXED32 = 5; /** @@ -51,32 +127,147 @@ public abstract class ProtoStream { */ public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT; + /** + * Not a real wire type. + * @hide + */ public static final long FIELD_TYPE_UNKNOWN = 0; + + /* + * The FIELD_TYPE_ constants are copied from + * external/protobuf/src/google/protobuf/descriptor.h directly, so no + * extra mapping needs to be maintained in this case. + */ + /** - * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly, - * so no extra mapping needs to be maintained in this case. + * Field type code for double fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, double) + * ProtoOutputStream.write(long, double)} method. */ public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT; + + /** + * Field type code for float fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, float) + * ProtoOutputStream.write(long, float)} method. + */ public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT; + + /** + * Field type code for int64 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, long) + * ProtoOutputStream.write(long, long)} method. + */ public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT; + + /** + * Field type code for uint64 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, long) + * ProtoOutputStream.write(long, long)} method. + */ public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT; + + /** + * Field type code for int32 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, int) + * ProtoOutputStream.write(long, int)} method. + */ public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT; + + /** + * Field type code for fixed64 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, long) + * ProtoOutputStream.write(long, long)} method. + */ public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT; + + /** + * Field type code for fixed32 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, int) + * ProtoOutputStream.write(long, int)} method. + */ + + /** + * Field type code for fixed32 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, int) + * ProtoOutputStream.write(long, int)} method. + */ public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT; + + /** + * Field type code for bool fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, boolean) + * ProtoOutputStream.write(long, boolean)} method. + */ public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT; + + /** + * Field type code for string fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, String) + * ProtoOutputStream.write(long, String)} method. + */ public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT; + // public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated. + + /** + * Field type code for message fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#start(long) + * ProtoOutputStream.start(long)} method. + */ public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT; + + /** + * Field type code for bytes fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, byte[]) + * ProtoOutputStream.write(long, byte[])} method. + */ public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT; + + /** + * Field type code for uint32 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, int) + * ProtoOutputStream.write(long, int)} method. + */ public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT; + + /** + * Field type code for enum fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, int) + * ProtoOutputStream.write(long, int)} method. + */ public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT; + + /** + * Field type code for sfixed32 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, int) + * ProtoOutputStream.write(long, int)} method. + */ public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT; + + /** + * Field type code for sfixed64 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, long) + * ProtoOutputStream.write(long, long)} method. + */ public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT; + + /** + * Field type code for sint32 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, int) + * ProtoOutputStream.write(long, int)} method. + */ public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT; + + /** + * Field type code for sint64 fields. Used to build constants in generated + * code for use with the {@link ProtoOutputStream#write(long, long) + * ProtoOutputStream.write(long, long)} method. + */ public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT; - protected static final String[] FIELD_TYPE_NAMES = new String[]{ + private static final @NonNull String[] FIELD_TYPE_NAMES = new String[]{ "Double", "Float", "Int64", @@ -100,19 +291,94 @@ public abstract class ProtoStream { // // FieldId flags for whether the field is single, repeated or packed. // + /** + * Bit offset for building a field id to be used with a + * <code>{@link ProtoOutputStream}.write(...)</code>. + * + * @see #FIELD_COUNT_MASK + * @see #FIELD_COUNT_UNKNOWN + * @see #FIELD_COUNT_SINGLE + * @see #FIELD_COUNT_REPEATED + * @see #FIELD_COUNT_PACKED + */ public static final int FIELD_COUNT_SHIFT = 40; + + /** + * Bit mask for selecting the field count when reading a field id that + * is used with a <code>{@link ProtoOutputStream}.write(...)</code> method. + * + * @see #FIELD_COUNT_SHIFT + * @see #FIELD_COUNT_MASK + * @see #FIELD_COUNT_UNKNOWN + * @see #FIELD_COUNT_SINGLE + * @see #FIELD_COUNT_REPEATED + * @see #FIELD_COUNT_PACKED + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT; + /** + * Unknown field count, encoded into a field id used with a + * <code>{@link ProtoOutputStream}.write(...)</code> method. + * + * @see #FIELD_COUNT_SHIFT + * @see #FIELD_COUNT_MASK + * @see #FIELD_COUNT_SINGLE + * @see #FIELD_COUNT_REPEATED + * @see #FIELD_COUNT_PACKED + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final long FIELD_COUNT_UNKNOWN = 0; + + /** + * Single field count, encoded into a field id used with a + * <code>{@link ProtoOutputStream}.write(...)</code> method. + * + * @see #FIELD_COUNT_SHIFT + * @see #FIELD_COUNT_MASK + * @see #FIELD_COUNT_UNKNOWN + * @see #FIELD_COUNT_REPEATED + * @see #FIELD_COUNT_PACKED + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT; + + /** + * Repeated field count, encoded into a field id used with a + * <code>{@link ProtoOutputStream}.write(...)</code> method. + * + * @see #FIELD_COUNT_SHIFT + * @see #FIELD_COUNT_MASK + * @see #FIELD_COUNT_UNKNOWN + * @see #FIELD_COUNT_SINGLE + * @see #FIELD_COUNT_PACKED + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT; + + /** + * Repeated packed field count, encoded into a field id used with a + * <code>{@link ProtoOutputStream}.write(...)</code> method. + * + * @see #FIELD_COUNT_SHIFT + * @see #FIELD_COUNT_MASK + * @see #FIELD_COUNT_UNKNOWN + * @see #FIELD_COUNT_SINGLE + * @see #FIELD_COUNT_REPEATED + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT; /** * Get the developer-usable name of a field type. */ - public static String getFieldTypeString(long fieldType) { + public static @Nullable String getFieldTypeString(long fieldType) { int index = ((int) ((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1; if (index >= 0 && index < FIELD_TYPE_NAMES.length) { return FIELD_TYPE_NAMES[index]; @@ -124,7 +390,7 @@ public abstract class ProtoStream { /** * Get the developer-usable name of a field count. */ - public static String getFieldCountString(long fieldCount) { + public static @Nullable String getFieldCountString(long fieldCount) { if (fieldCount == FIELD_COUNT_SINGLE) { return ""; } else if (fieldCount == FIELD_COUNT_REPEATED) { @@ -139,7 +405,7 @@ public abstract class ProtoStream { /** * Get the developer-usable name of a wire type. */ - public static String getWireTypeString(int wireType) { + public static @Nullable String getWireTypeString(int wireType) { switch (wireType) { case WIRE_TYPE_VARINT: return "Varint"; @@ -161,7 +427,7 @@ public abstract class ProtoStream { /** * Get a debug string for a fieldId. */ - public static String getFieldIdString(long fieldId) { + public static @NonNull String getFieldIdString(long fieldId) { final long fieldCount = fieldId & FIELD_COUNT_MASK; String countString = getFieldCountString(fieldCount); if (countString == null) { @@ -218,29 +484,39 @@ public abstract class ProtoStream { /** * Get the encoded tag size from the token. + * + * @hide */ public static int getTagSizeFromToken(long token) { return (int) (0x7 & (token >> 61)); } /** - * Get whether this is a call to startObject (false) or startRepeatedObject (true). + * Get whether the token has the repeated bit set to true or false + * + * @hide */ public static boolean getRepeatedFromToken(long token) { return (0x1 & (token >> 60)) != 0; } /** - * Get the nesting depth of startObject calls from the token. + * Get the nesting depth from the token. + * + * @hide */ public static int getDepthFromToken(long token) { return (int) (0x01ff & (token >> 51)); } /** - * Get the object ID from the token. The object ID is a serial number for the + * Get the object ID from the token. + * + * <p>The object ID is a serial number for the * startObject calls that have happened on this object. The values are truncated * to 9 bits, but that is sufficient for error checking. + * + * @hide */ public static int getObjectIdFromToken(long token) { return (int) (0x07ffff & (token >> 32)); @@ -248,6 +524,8 @@ public abstract class ProtoStream { /** * Get the location of the offset recorded in the token. + * + * @hide */ public static int getOffsetFromToken(long token) { return (int) token; @@ -255,8 +533,11 @@ public abstract class ProtoStream { /** * Convert the object ID to the ordinal value -- the n-th call to startObject. - * The object IDs start at -1 and count backwards, so that the value is unlikely + * + * <p>The object IDs start at -1 and count backwards, so that the value is unlikely * to alias with an actual size field that had been written. + * + * @hide */ public static int convertObjectIdToOrdinal(int objectId) { return (-1 & 0x07ffff) - objectId; @@ -265,7 +546,7 @@ public abstract class ProtoStream { /** * Return a debugging string of a token. */ - public static String token2String(long token) { + public static @NonNull String token2String(long token) { if (token == 0L) { return "Token(0)"; } else { @@ -277,4 +558,9 @@ public abstract class ProtoStream { + ')'; } } + + /** + * @hide + */ + protected ProtoStream() {} } diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java index 03bf590902c0..a71561b7614b 100644 --- a/core/java/android/util/proto/ProtoUtils.java +++ b/core/java/android/util/proto/ProtoUtils.java @@ -24,12 +24,12 @@ import java.io.IOException; /** * This class contains a list of helper functions to write common proto in * //frameworks/base/core/proto/android/base directory + * @hide */ public class ProtoUtils { /** * Dump AggStats to ProtoOutputStream - * @hide */ public static void toAggStatsProto(ProtoOutputStream proto, long fieldId, long min, long average, long max) { @@ -42,7 +42,6 @@ public class ProtoUtils { /** * Dump Duration to ProtoOutputStream - * @hide */ public static void toDuration(ProtoOutputStream proto, long fieldId, long startMs, long endMs) { final long token = proto.start(fieldId); @@ -53,7 +52,6 @@ public class ProtoUtils { /** * Helper function to write bit-wise flags to proto as repeated enums - * @hide */ public static void writeBitWiseFlagsToProtoEnum(ProtoOutputStream proto, long fieldId, int flags, int[] origEnums, int[] protoEnums) { diff --git a/core/java/android/util/proto/package.html b/core/java/android/util/proto/package.html index a636bd457d3d..ef1125b5f248 100644 --- a/core/java/android/util/proto/package.html +++ b/core/java/android/util/proto/package.html @@ -1,5 +1,5 @@ +<html> <body> Provides utility classes to export protocol buffers from the system. - -{@hide} </body> +</html>
\ No newline at end of file diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java index 5f9bf39fb3dd..bee04f4d8036 100644 --- a/core/java/android/view/AccessibilityIterators.java +++ b/core/java/android/view/AccessibilityIterators.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Configuration; import java.text.BreakIterator; diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java index 6b200e1af39a..d9f9d039f507 100644 --- a/core/java/android/view/ActionMode.java +++ b/core/java/android/view/ActionMode.java @@ -19,10 +19,9 @@ package android.view; import android.annotation.StringRes; import android.annotation.TestApi; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; -import dalvik.annotation.compat.UnsupportedAppUsage; - /** * Represents a contextual mode of the user interface. Action modes can be used to provide * alternative interaction modes and replace parts of the normal UI until finished. diff --git a/core/java/android/view/ActionProvider.java b/core/java/android/view/ActionProvider.java index cd7e67e61b61..e1be0fe8d6d2 100644 --- a/core/java/android/view/ActionProvider.java +++ b/core/java/android/view/ActionProvider.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.Log; diff --git a/core/java/android/view/AppTransitionAnimationSpec.java b/core/java/android/view/AppTransitionAnimationSpec.java index 4c0ed52946bd..330061f068f8 100644 --- a/core/java/android/view/AppTransitionAnimationSpec.java +++ b/core/java/android/view/AppTransitionAnimationSpec.java @@ -1,6 +1,6 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.GraphicBuffer; import android.graphics.Rect; import android.os.Parcel; diff --git a/core/java/android/view/BatchedInputEventReceiver.java b/core/java/android/view/BatchedInputEventReceiver.java index 61ccac991eea..95b2c7019dbc 100644 --- a/core/java/android/view/BatchedInputEventReceiver.java +++ b/core/java/android/view/BatchedInputEventReceiver.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; /** diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 28eb79ae1f2a..5b4ff52376b3 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -16,12 +16,11 @@ package android.view; -import static android.view.DisplayEventReceiver.CONFIG_CHANGED_EVENT_SUPPRESS; import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP; import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.FrameInfo; import android.hardware.display.DisplayManagerGlobal; import android.os.Build; diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java index 696e048ffed8..876331b5c57f 100644 --- a/core/java/android/view/ContextThemeWrapper.java +++ b/core/java/android/view/ContextThemeWrapper.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.ContextWrapper; import android.content.res.AssetManager; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index b3d98b8de0a3..7a818ce78568 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -22,8 +22,8 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java index da4d92fa0c94..834dd7b6e7d8 100644 --- a/core/java/android/view/DisplayAdjustments.java +++ b/core/java/android/view/DisplayAdjustments.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 91acc4638c26..eaf297cc05d8 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import android.util.Log; diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 2efebf6457ab..f3b2800eef39 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -23,7 +23,7 @@ import static android.view.DisplayInfoProto.LOGICAL_WIDTH; import static android.view.DisplayInfoProto.NAME; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Rect; diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java index 8e6e99a6d949..6035cbebb032 100644 --- a/core/java/android/view/DisplayListCanvas.java +++ b/core/java/android/view/DisplayListCanvas.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.BaseRecordingCanvas; import android.graphics.CanvasProperty; import android.graphics.Paint; diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java index 2a43bcc00daf..35af0f252d2d 100644 --- a/core/java/android/view/DragEvent.java +++ b/core/java/android/view/DragEvent.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; import android.os.Parcel; diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java index dcdef3eaa275..de4112cbf1e1 100644 --- a/core/java/android/view/FrameMetrics.java +++ b/core/java/android/view/FrameMetrics.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java index 0f38e847f4bd..e4197abf8088 100644 --- a/core/java/android/view/FrameMetricsObserver.java +++ b/core/java/android/view/FrameMetricsObserver.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index 8fbbcf4b88c6..0fdbc9cf9e33 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -23,7 +23,7 @@ import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SC import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java index 3286bd623694..a72832760f96 100644 --- a/core/java/android/view/GhostView.java +++ b/core/java/android/view/GhostView.java @@ -15,7 +15,7 @@ */ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.RecordingCanvas; diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java index ecb727c79016..67c8b15b2ca5 100644 --- a/core/java/android/view/InputChannel.java +++ b/core/java/android/view/InputChannel.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index e723f91887c1..360deddf544d 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.RequiresPermission; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java index 4b88a6a54efe..5f9c4801ee66 100644 --- a/core/java/android/view/InputEvent.java +++ b/core/java/android/view/InputEvent.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java index e4b1a8d855ec..c0a3cec4547a 100644 --- a/core/java/android/view/InputEventConsistencyVerifier.java +++ b/core/java/android/view/InputEventConsistencyVerifier.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.util.Log; diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 7260a658a027..cab8bc549af6 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import android.util.Log; diff --git a/core/java/android/view/InputEventSender.java b/core/java/android/view/InputEventSender.java index c5f4c23b7b15..86a309e3ed79 100644 --- a/core/java/android/view/InputEventSender.java +++ b/core/java/android/view/InputEventSender.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import android.util.Log; diff --git a/core/java/android/view/InputFilter.java b/core/java/android/view/InputFilter.java index 3aaf31ef406f..36d558630da9 100644 --- a/core/java/android/view/InputFilter.java +++ b/core/java/android/view/InputFilter.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; import android.os.Message; diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java index 69ebc46cb456..74ce6ac02db3 100644 --- a/core/java/android/view/InputQueue.java +++ b/core/java/android/view/InputQueue.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import android.util.LongSparseArray; diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java index bd033480ea87..90e0f3f89a0f 100644 --- a/core/java/android/view/KeyCharacterMap.java +++ b/core/java/android/view/KeyCharacterMap.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.input.InputManager; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 60db6a57d187..c638717b13c0 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -20,7 +20,7 @@ import static android.view.Display.INVALID_DISPLAY; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 1fc7f0e36095..bf646c7cddb6 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Resources; @@ -31,10 +31,7 @@ import android.graphics.Canvas; import android.os.Build; import android.os.Handler; import android.os.Message; -import android.os.SystemProperties; import android.os.Trace; -import android.provider.DeviceConfig; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 833e78ff5c71..70873d7db92a 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -22,7 +22,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Matrix; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index b2f3f5edcd20..232e0f6f9a14 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -17,9 +17,9 @@ package android.view; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.AppOpsManager; import android.app.Notification; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index dfe34c80bb8f..18d0d7b98a42 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -17,8 +17,8 @@ package android.view; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index c686440171a2..166d3baa2fdf 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -16,8 +16,8 @@ package android.view; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityOptions; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java index da599efb6eee..c9bd92ae84ba 100644 --- a/core/java/android/view/RemoteAnimationDefinition.java +++ b/core/java/android/view/RemoteAnimationDefinition.java @@ -19,9 +19,9 @@ package android.view; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.WindowConfiguration; import android.app.WindowConfiguration.ActivityType; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java index ae3e1d0a9691..2249966a6b2d 100644 --- a/core/java/android/view/RemoteAnimationTarget.java +++ b/core/java/android/view/RemoteAnimationTarget.java @@ -30,8 +30,8 @@ import static android.view.RemoteAnimationTargetProto.TASK_ID; import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; import android.app.WindowConfiguration; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Point; import android.graphics.Rect; import android.os.Parcel; diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index 93f52a04d626..06cb51927ba8 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -19,7 +19,7 @@ package android.view; import android.animation.Animator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.CanvasProperty; import android.graphics.Paint; import android.graphics.RecordingCanvas; diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 1d721516a979..346f76cace7d 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 17f07b5a2ad4..3a6c8dd3720f 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo.Translator; import android.graphics.Canvas; import android.graphics.ColorSpace; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 2313b13befad..2c48af04aa18 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -32,7 +32,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java index 361ac932758e..0f851c1881f5 100644 --- a/core/java/android/view/SurfaceSession.java +++ b/core/java/android/view/SurfaceSession.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An instance of this class represents a connection to the surface diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index d11548d687b1..ec2ab6a5a4be 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -20,7 +20,7 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLA import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER; import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.CompatibilityInfo.Translator; import android.graphics.BlendMode; diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 0175ba201dd1..2062bb0bc87f 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java index 2ea95e90a8bf..de0f9e5c5cf6 100644 --- a/core/java/android/view/TouchDelegate.java +++ b/core/java/android/view/TouchDelegate.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.graphics.Region; import android.util.ArrayMap; diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java index 7154f2bdee42..a56633e3c5fa 100644 --- a/core/java/android/view/VelocityTracker.java +++ b/core/java/android/view/VelocityTracker.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Pools.SynchronizedPool; /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 9d2040c5bdb4..3313537965c4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -43,7 +43,7 @@ import android.annotation.Size; import android.annotation.StyleRes; import android.annotation.TestApi; import android.annotation.UiThread; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.AutofillOptions; import android.content.ClipData; import android.content.Context; diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 9e914d4e7d41..774a2dea6311 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -18,8 +18,8 @@ package android.view; import android.annotation.FloatRange; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.AppGlobals; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 8a1fd62c0201..dda7b260533e 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -19,7 +19,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -870,6 +870,94 @@ public class ViewDebug { return null; } + private static class StreamingPictureCallbackHandler implements AutoCloseable, + HardwareRenderer.PictureCapturedCallback, Runnable { + private final HardwareRenderer mRenderer; + private final Callable<OutputStream> mCallback; + private final Executor mExecutor; + private final ReentrantLock mLock = new ReentrantLock(false); + private final ArrayDeque<byte[]> mQueue = new ArrayDeque<>(3); + private final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream(); + private boolean mStopListening; + private Thread mRenderThread; + + private StreamingPictureCallbackHandler(HardwareRenderer renderer, + Callable<OutputStream> callback, Executor executor) { + mRenderer = renderer; + mCallback = callback; + mExecutor = executor; + mRenderer.setPictureCaptureCallback(this); + } + + @Override + public void close() { + mLock.lock(); + mStopListening = true; + mLock.unlock(); + mRenderer.setPictureCaptureCallback(null); + } + + @Override + public void onPictureCaptured(Picture picture) { + mLock.lock(); + if (mStopListening) { + mLock.unlock(); + mRenderer.setPictureCaptureCallback(null); + return; + } + if (mRenderThread == null) { + mRenderThread = Thread.currentThread(); + } + boolean needsInvoke = true; + if (mQueue.size() == 3) { + mQueue.removeLast(); + needsInvoke = false; + } + picture.writeToStream(mByteStream); + mQueue.add(mByteStream.toByteArray()); + mByteStream.reset(); + mLock.unlock(); + + if (needsInvoke) { + mExecutor.execute(this); + } + } + + @Override + public void run() { + mLock.lock(); + final byte[] picture = mQueue.poll(); + final boolean isStopped = mStopListening; + mLock.unlock(); + if (Thread.currentThread() == mRenderThread) { + close(); + throw new IllegalStateException( + "ViewDebug#startRenderingCommandsCapture must be given an executor that " + + "invokes asynchronously"); + } + if (isStopped) { + return; + } + OutputStream stream = null; + try { + stream = mCallback.call(); + } catch (Exception ex) { + Log.w("ViewDebug", "Aborting rendering commands capture " + + "because callback threw exception", ex); + } + if (stream != null) { + try { + stream.write(picture); + } catch (IOException ex) { + Log.w("ViewDebug", "Aborting rendering commands capture " + + "due to IOException writing to output stream", ex); + } + } else { + close(); + } + } + } + /** * Begins capturing the entire rendering commands for the view tree referenced by the given * view. The view passed may be any View in the tree as long as it is attached. That is, @@ -915,18 +1003,7 @@ public class ViewDebug { } final HardwareRenderer renderer = attachInfo.mThreadedRenderer; if (renderer != null) { - return new PictureCallbackHandler(renderer, (picture -> { - try { - OutputStream stream = callback.call(); - if (stream != null) { - picture.writeToStream(stream); - return true; - } - } catch (Exception ex) { - // fall through - } - return false; - }), executor); + return new StreamingPictureCallbackHandler(renderer, callback, executor); } return null; } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 937bd1b34e61..6125aadc57b6 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -24,7 +24,7 @@ import android.annotation.IdRes; import android.annotation.NonNull; import android.annotation.TestApi; import android.annotation.UiThread; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/view/ViewHierarchyEncoder.java b/core/java/android/view/ViewHierarchyEncoder.java index d5716bfaaf00..b0e0524a0d85 100644 --- a/core/java/android/view/ViewHierarchyEncoder.java +++ b/core/java/android/view/ViewHierarchyEncoder.java @@ -2,7 +2,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java index e23c687af49b..7830c57e53ec 100644 --- a/core/java/android/view/ViewOverlay.java +++ b/core/java/android/view/ViewOverlay.java @@ -17,7 +17,7 @@ package android.view; import android.animation.LayoutTransition; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 57a01a32e1b8..1ab3d3ab4974 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -32,10 +32,10 @@ import android.animation.LayoutTransition; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ResourcesManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; import android.content.Context; diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java index c72baca0b93b..d7b0afc89eaa 100644 --- a/core/java/android/view/ViewTreeObserver.java +++ b/core/java/android/view/ViewTreeObserver.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.graphics.Region; diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 73e0e4b2eb8b..cdafa470a542 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -26,8 +26,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.WindowConfiguration; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; diff --git a/core/java/android/view/WindowAnimationFrameStats.java b/core/java/android/view/WindowAnimationFrameStats.java index 399dfba64461..dfc4f0cd4dc6 100644 --- a/core/java/android/view/WindowAnimationFrameStats.java +++ b/core/java/android/view/WindowAnimationFrameStats.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/WindowContentFrameStats.java b/core/java/android/view/WindowContentFrameStats.java index 9fa5a005055d..217197c96793 100644 --- a/core/java/android/view/WindowContentFrameStats.java +++ b/core/java/android/view/WindowContentFrameStats.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index bcc6a552f569..87bc534da92f 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -34,7 +34,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.graphics.Insets; import android.graphics.Rect; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 7433b6c8ce87..d9d92788a434 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -50,9 +50,9 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; import android.app.Presentation; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.PixelFormat; diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 379acbecb613..a930abe40341 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -18,8 +18,8 @@ package android.view; import android.animation.ValueAnimator; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index c3494432ebcb..cdeeaa438acb 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Region; import android.os.Bundle; diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 2ac44d2fac22..2ba9f94869e4 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -17,7 +17,7 @@ package android.view.accessibility; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 4db6f4f808f2..723da77b6f7d 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -17,7 +17,7 @@ package android.view.accessibility; import android.accessibilityservice.IAccessibilityServiceConnection; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Build; import android.os.Bundle; diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 2e9d881f72f9..747bd706f316 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -29,7 +29,7 @@ import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 3b310fc13ee3..8e61a5e7c44b 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -26,7 +26,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.graphics.Region; import android.os.Bundle; diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java index b382a1863af3..37c3a1361de1 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -19,7 +19,7 @@ package android.view.accessibility; import static com.android.internal.util.CollectionUtils.isEmpty; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcelable; import android.view.View; diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java index c42e9fec91bf..3d68692a3b5c 100644 --- a/core/java/android/view/accessibility/CaptioningManager.java +++ b/core/java/android/view/accessibility/CaptioningManager.java @@ -19,7 +19,7 @@ package android.view.accessibility; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index 3b60aee8f604..43dcafc9b9ce 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -19,7 +19,7 @@ package android.view.animation; import android.annotation.AnimRes; import android.annotation.ColorInt; import android.annotation.InterpolatorRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.RectF; diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index c877b9cec812..075b0ab728fa 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -19,7 +19,7 @@ package android.view.animation; import android.annotation.AnimRes; import android.annotation.InterpolatorRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java index 58da04d8d38f..cfc6e39da876 100644 --- a/core/java/android/view/animation/Transformation.java +++ b/core/java/android/view/animation/Transformation.java @@ -17,7 +17,7 @@ package android.view.animation; import android.annotation.FloatRange; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Matrix; import android.graphics.Rect; diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java index 6c040d4c61aa..ec55a0273999 100644 --- a/core/java/android/view/animation/TranslateAnimation.java +++ b/core/java/android/view/animation/TranslateAnimation.java @@ -16,7 +16,7 @@ package android.view.animation; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; diff --git a/core/java/android/view/animation/TranslateYAnimation.java b/core/java/android/view/animation/TranslateYAnimation.java index a6e0ccb18805..1a1dfbfd6f05 100644 --- a/core/java/android/view/animation/TranslateYAnimation.java +++ b/core/java/android/view/animation/TranslateYAnimation.java @@ -16,7 +16,7 @@ package android.view.animation; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Matrix; /** diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index fe07feef3bfa..34005ac02735 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -17,7 +17,7 @@ package android.view.inputmethod; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 032af1c5c7b5..d395f5294d6c 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -26,9 +26,9 @@ import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -2830,7 +2830,7 @@ public final class InputMethodManager { } /** - * This is kept due to {@link android.annotation.UnsupportedAppUsage}. + * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage}. * * <p>TODO(Bug 113914148): Check if we can remove this. We have accidentally exposed * WindowManagerInternal#getInputMethodWindowVisibleHeight to app developers and some of them diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java index 8dd0dcd45a1c..50e95c80cfed 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java +++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java @@ -16,7 +16,7 @@ package android.view.inputmethod; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.util.Slog; diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java index 95ca9deb2871..526ac6fd3570 100644 --- a/core/java/android/view/textclassifier/TextClassificationManager.java +++ b/core/java/android/view/textclassifier/TextClassificationManager.java @@ -19,8 +19,8 @@ package android.view.textclassifier; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.database.ContentObserver; import android.os.ServiceManager; diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java index b530ddfe86d6..05d12ce17d8c 100644 --- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java +++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java @@ -19,7 +19,7 @@ package android.view.textclassifier.logging; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.metrics.LogMaker; import android.util.Log; diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java index f553ca512881..afddaa2ff58a 100644 --- a/core/java/android/view/textservice/SpellCheckerSession.java +++ b/core/java/android/view/textservice/SpellCheckerSession.java @@ -16,7 +16,7 @@ package android.view.textservice; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java index 9ff64d9b268a..acb35d63df9d 100644 --- a/core/java/android/view/textservice/TextServicesManager.java +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -18,8 +18,8 @@ package android.view.textservice; import android.annotation.NonNull; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index 7e067197ced8..fafe81393888 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.File; import java.io.IOException; diff --git a/core/java/android/webkit/ConsoleMessage.java b/core/java/android/webkit/ConsoleMessage.java index e54849772f9a..5474557c9998 100644 --- a/core/java/android/webkit/ConsoleMessage.java +++ b/core/java/android/webkit/ConsoleMessage.java @@ -16,7 +16,7 @@ package android.webkit; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; /** diff --git a/core/java/android/webkit/JsResult.java b/core/java/android/webkit/JsResult.java index 5bf6aab3225d..448db58e2658 100644 --- a/core/java/android/webkit/JsResult.java +++ b/core/java/android/webkit/JsResult.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An instance of this class is passed as a parameter in various {@link WebChromeClient} action diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java index 8aeeb1c53241..c9a196017a75 100644 --- a/core/java/android/webkit/PluginData.java +++ b/core/java/android/webkit/PluginData.java @@ -16,7 +16,8 @@ package android.webkit; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.InputStream; import java.util.Map; diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java index 5d704cb09dcb..844b156b84d3 100644 --- a/core/java/android/webkit/URLUtil.java +++ b/core/java/android/webkit/URLUtil.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.ParseException; import android.net.Uri; import android.net.WebAddress; diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java index f23aae6be8c2..a48e10799be7 100644 --- a/core/java/android/webkit/UrlInterceptHandler.java +++ b/core/java/android/webkit/UrlInterceptHandler.java @@ -17,9 +17,8 @@ package android.webkit; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.webkit.CacheManager.CacheResult; -import android.webkit.PluginData; import java.util.Map; diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java index eeb28d73be85..c9dee00942c3 100644 --- a/core/java/android/webkit/UrlInterceptRegistry.java +++ b/core/java/android/webkit/UrlInterceptRegistry.java @@ -17,10 +17,8 @@ package android.webkit; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.webkit.CacheManager.CacheResult; -import android.webkit.PluginData; -import android.webkit.UrlInterceptHandler; import java.util.Iterator; import java.util.LinkedList; diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java index 7c8f33e181d6..219523b15ab0 100644 --- a/core/java/android/webkit/WebResourceResponse.java +++ b/core/java/android/webkit/WebResourceResponse.java @@ -18,7 +18,7 @@ package android.webkit; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.InputStream; import java.io.StringBufferInputStream; diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 7282008f7e3a..8a5b64d95f19 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -19,7 +19,7 @@ package android.webkit; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import java.lang.annotation.ElementType; diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java index e44d6ebf37d1..7046c5108783 100644 --- a/core/java/android/webkit/WebSyncManager.java +++ b/core/java/android/webkit/WebSyncManager.java @@ -16,7 +16,7 @@ package android.webkit; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; /** diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 721ac2d9a6dc..271d5be3864e 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -21,8 +21,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java index f5657dff538f..df86926a95dc 100644 --- a/core/java/android/webkit/WebViewDelegate.java +++ b/core/java/android/webkit/WebViewDelegate.java @@ -19,10 +19,10 @@ package android.webkit; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.Application; import android.app.ResourcesManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Resources; diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 678a25223ef5..941af6ef1d7a 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -17,10 +17,10 @@ package android.webkit; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.Application; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java index 7e00cded2c5a..6629fdc4cdee 100644 --- a/core/java/android/webkit/WebViewProviderInfo.java +++ b/core/java/android/webkit/WebViewProviderInfo.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.Signature; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/webkit/WebViewProviderResponse.java b/core/java/android/webkit/WebViewProviderResponse.java index 5622abe0e99f..b58cc4bb1577 100644 --- a/core/java/android/webkit/WebViewProviderResponse.java +++ b/core/java/android/webkit/WebViewProviderResponse.java @@ -16,7 +16,7 @@ package android.webkit; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.PackageInfo; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java index 12d3221fb7b5..9152b438618f 100644 --- a/core/java/android/webkit/WebViewUpdateService.java +++ b/core/java/android/webkit/WebViewUpdateService.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.RemoteException; /** diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 85e9e4950cba..2d99eab88dfc 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -20,7 +20,7 @@ import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index bbcba2e12a2c..11a6acf5b934 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java index cfb93ec2321f..aa3590aaff0a 100644 --- a/core/java/android/widget/ActionMenuPresenter.java +++ b/core/java/android/widget/ActionMenuPresenter.java @@ -22,7 +22,7 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java index 7e58622db3b8..3a743562110f 100644 --- a/core/java/android/widget/ActionMenuView.java +++ b/core/java/android/widget/ActionMenuView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java index f5bf7598aa5a..d87bdf482e43 100644 --- a/core/java/android/widget/ActivityChooserModel.java +++ b/core/java/android/widget/ActivityChooserModel.java @@ -16,8 +16,8 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java index 89ea0747b532..aa18d576c8f4 100644 --- a/core/java/android/widget/ActivityChooserView.java +++ b/core/java/android/widget/ActivityChooserView.java @@ -17,7 +17,7 @@ package android.widget; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index c55f7d654548..52658404548c 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.database.DataSetObserver; import android.os.Build; diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 67a70b48b534..d165bd0f0fa7 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index 2bf1ba5cf017..6c38c8b9a0f5 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -21,7 +21,7 @@ import android.annotation.IdRes; import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.util.Log; diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 8785251b0a64..8d9ae58be290 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.DrawableRes; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources.Theme; import android.content.res.TypedArray; diff --git a/core/java/android/widget/BaseAdapter.java b/core/java/android/widget/BaseAdapter.java index 7b9365b08a41..27cf9a64a8d5 100644 --- a/core/java/android/widget/BaseAdapter.java +++ b/core/java/android/widget/BaseAdapter.java @@ -17,7 +17,7 @@ package android.widget; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.DataSetObservable; import android.database.DataSetObserver; import android.view.View; diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index b552aa6c85c4..4b2f738ef7ab 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -23,8 +23,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index 8b70f41f050c..422d2d37321c 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -19,7 +19,7 @@ package android.widget; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index 2674ca4d159a..52e983ec487d 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -19,7 +19,7 @@ package android.widget; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java index e250f63bbc65..600a34c33eb9 100644 --- a/core/java/android/widget/CursorAdapter.java +++ b/core/java/android/widget/CursorAdapter.java @@ -16,8 +16,8 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.database.ContentObserver; diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 0c593be1ee7d..c1c1a6e88b50 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -19,8 +19,8 @@ package android.widget; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java index 5f151105622e..096e6ea52c8a 100644 --- a/core/java/android/widget/DatePickerSpinnerDelegate.java +++ b/core/java/android/widget/DatePickerSpinnerDelegate.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java index 2864ad0b7932..20a53c03bed1 100644 --- a/core/java/android/widget/DateTimeView.java +++ b/core/java/android/widget/DateTimeView.java @@ -21,8 +21,8 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.YEAR_IN_MILLIS; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index fa0af78694ab..32f3acd387b0 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.ColorInt; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.BlendMode; diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index cac75cfd8432..b6338f7b0e7a 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -21,10 +21,10 @@ import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.app.RemoteAction; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipData.Item; import android.content.Context; diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java index cae91fce64a3..bdfb5503946d 100644 --- a/core/java/android/widget/ExpandableListView.java +++ b/core/java/android/widget/ExpandableListView.java @@ -18,7 +18,7 @@ package android.widget; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index 2c09185fdf62..0c0b3491a854 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -23,7 +23,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java index 16f4ee2b51d6..06e6a5ac694f 100644 --- a/core/java/android/widget/Filter.java +++ b/core/java/android/widget/Filter.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index 69da9112ca01..92e9a96e4897 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -20,7 +20,7 @@ import android.annotation.AttrRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index 64192aaff1cf..8c0061d6e750 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -17,8 +17,8 @@ package android.widget; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 8cda47dae39b..f1321979e2de 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -31,7 +31,7 @@ import static java.lang.Math.max; import static java.lang.Math.min; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 4e39a559c6ea..4a5e95e492e5 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; diff --git a/core/java/android/widget/HeaderViewListAdapter.java b/core/java/android/widget/HeaderViewListAdapter.java index 10d50b811289..eda7580949b1 100644 --- a/core/java/android/widget/HeaderViewListAdapter.java +++ b/core/java/android/widget/HeaderViewListAdapter.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.DataSetObserver; import android.view.View; import android.view.ViewGroup; diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 5921feb7a758..f5f64c033692 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.ColorInt; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index d62b979a2ed3..c20773848759 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -20,7 +20,7 @@ import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.res.ColorStateList; diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index a83e82699938..a796ba545d8f 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -19,7 +19,7 @@ package android.widget; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 16b903d4da9e..001eb2728fec 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -20,7 +20,7 @@ import android.annotation.AttrRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.database.DataSetObserver; diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 2f44d6ee88b1..72603444f5ff 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -19,7 +19,7 @@ package android.widget; import android.annotation.IdRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index 65925b446bbe..9c9baf35949b 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.graphics.PixelFormat; diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index b385534f1850..b2fedf7a3a7f 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -23,8 +23,8 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.Px; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java index e7a96bea18fe..1c33d80fd4ca 100644 --- a/core/java/android/widget/OverScroller.java +++ b/core/java/android/widget/OverScroller.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.hardware.SensorManager; import android.util.Log; diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java index b0c0c12e907a..0ce964666a2b 100644 --- a/core/java/android/widget/PopupMenu.java +++ b/core/java/android/widget/PopupMenu.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.MenuRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.view.Gravity; import android.view.Menu; diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 3779779e9f21..bf696f5a7c53 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -18,13 +18,12 @@ package android.widget; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static android.view.WindowManager.LayoutParams - .PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.PixelFormat; diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 2e9574345692..9cbb03508d67 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -21,7 +21,7 @@ import android.annotation.InterpolatorRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java index c1a217c6dc89..ea39f6d71573 100644 --- a/core/java/android/widget/QuickContactBadge.java +++ b/core/java/android/widget/QuickContactBadge.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.AsyncQueryHandler; import android.content.ContentResolver; import android.content.Context; diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java index c62c16c7e719..69c3cdad2dbf 100644 --- a/core/java/android/widget/RadioGroup.java +++ b/core/java/android/widget/RadioGroup.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.IdRes; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java index 3cf3d9102d21..f946fe6d8314 100644 --- a/core/java/android/widget/RatingBar.java +++ b/core/java/android/widget/RatingBar.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.shapes.RectShape; diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index b9da3071d895..521922df97e0 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -19,7 +19,7 @@ package android.widget; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ResourceId; import android.content.res.TypedArray; diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 86cec5e0f0a2..82e03e26b41f 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -22,7 +22,6 @@ import android.annotation.IntDef; import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.ActivityOptions; import android.app.ActivityThread; @@ -30,6 +29,7 @@ import android.app.Application; import android.app.PendingIntent; import android.app.RemoteInput; import android.appwidget.AppWidgetHostView; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index efc5eb373e00..e58f08a79965 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -19,11 +19,11 @@ package android.widget; import static android.widget.RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID; import static android.widget.RemoteViews.EXTRA_REMOTEADAPTER_ON_LIGHT_BACKGROUND; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; import android.app.IServiceConnection; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java index a5d3e45323a4..80e17b5e8217 100644 --- a/core/java/android/widget/ScrollBarDrawable.java +++ b/core/java/android/widget/ScrollBarDrawable.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 51b0950a7544..6c2e7a956ab9 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.ColorInt; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java index 229eaf0f8ff6..6ed5b7ebf4d0 100644 --- a/core/java/android/widget/Scroller.java +++ b/core/java/android/widget/Scroller.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.hardware.SensorManager; import android.os.Build; diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 89d9e97bddad..15959c221ffc 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -19,10 +19,10 @@ package android.widget; import static android.widget.SuggestionsAdapter.getColumnString; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.app.SearchManager; import android.app.SearchableInfo; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java index e8cf1e855a33..5676881cee76 100644 --- a/core/java/android/widget/SeekBar.java +++ b/core/java/android/widget/SeekBar.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.AttributeSet; import android.view.accessibility.AccessibilityNodeInfo; diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java index 15e1ffa7bc31..404b81795823 100644 --- a/core/java/android/widget/SimpleAdapter.java +++ b/core/java/android/widget/SimpleAdapter.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.IdRes; import android.annotation.LayoutRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.net.Uri; diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java index 77fe5d1a9302..6277d5b84913 100644 --- a/core/java/android/widget/SimpleCursorAdapter.java +++ b/core/java/android/widget/SimpleCursorAdapter.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.database.Cursor; import android.net.Uri; diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java index 2ab2b2407a50..9a4cfa192854 100644 --- a/core/java/android/widget/SlidingDrawer.java +++ b/core/java/android/widget/SlidingDrawer.java @@ -17,7 +17,7 @@ package android.widget; import android.R; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java index 92fcea348b1a..46fc09f4c3b3 100644 --- a/core/java/android/widget/Spinner.java +++ b/core/java/android/widget/Spinner.java @@ -19,9 +19,9 @@ package android.widget; import android.annotation.DrawableRes; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; import android.app.AlertDialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index d57b3bc7ad3b..f1f393973fed 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -21,7 +21,7 @@ import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java index 481704c80287..fd8dbf5c86f7 100644 --- a/core/java/android/widget/TabHost.java +++ b/core/java/android/widget/TabHost.java @@ -18,8 +18,8 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.LocalActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index 4c67b080252a..945cef3e5791 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.DrawableRes; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index b7dd88bcedc6..88a67625d615 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -21,8 +21,8 @@ import static android.widget.RemoteViews.RemoteView; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 0918c5fdefa8..6f697cd65686 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -36,11 +36,11 @@ import android.annotation.RequiresPermission; import android.annotation.Size; import android.annotation.StringRes; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; import android.app.Activity; import android.app.PendingIntent; import android.app.assist.AssistStructure; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; import android.content.ClipboardManager; diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index 8a5d5312bd7b..51b18473f1ac 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -20,8 +20,8 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.icu.util.Calendar; diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index d037337d4546..e6dcd9ef5817 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -20,9 +20,9 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; import android.app.INotificationManager; import android.app.ITransientNotification; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index a21fb41b7c99..ea3f06b7f3e2 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -24,8 +24,8 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActionBar; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index 40b0f13c596b..36dafd5c0a05 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -17,8 +17,8 @@ package android.widget; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.AlertDialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java index 80ea363a6ad6..909404b42f1d 100644 --- a/core/java/android/widget/ViewAnimator.java +++ b/core/java/android/widget/ViewAnimator.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.AnimRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java index b962298e3d46..2df9a785450b 100644 --- a/core/java/android/widget/ViewFlipper.java +++ b/core/java/android/widget/ViewFlipper.java @@ -17,7 +17,7 @@ package android.widget; import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/widget/ZoomControls.java b/core/java/android/widget/ZoomControls.java index 7a5b7e8058f3..f435533291d6 100644 --- a/core/java/android/widget/ZoomControls.java +++ b/core/java/android/widget/ZoomControls.java @@ -16,8 +16,8 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; diff --git a/core/java/com/android/ims/internal/uce/common/CapInfo.java b/core/java/com/android/ims/internal/uce/common/CapInfo.java index a9847ba61cf6..2bb3f1fed927 100644 --- a/core/java/com/android/ims/internal/uce/common/CapInfo.java +++ b/core/java/com/android/ims/internal/uce/common/CapInfo.java @@ -16,10 +16,9 @@ package com.android.ims.internal.uce.common; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; /** Class for capability discovery information. * @hide */ @@ -65,6 +64,20 @@ public class CapInfo implements Parcelable { private boolean mRcsIpVideoCallSupported = false; /** RCS IP Video call support . */ private boolean mRcsIpVideoOnlyCallSupported = false; + /** IP Geo location Push using SMS. */ + private boolean mGeoSmsSupported = false; + /** RCS call composer support. */ + private boolean mCallComposerSupported = false; + /** RCS post-call support. */ + private boolean mPostCallSupported = false; + /** Shared map support. */ + private boolean mSharedMapSupported = false; + /** Shared Sketch supported. */ + private boolean mSharedSketchSupported = false; + /** Chatbot communication support. */ + private boolean mChatbotSupported = false; + /** Chatbot role support. */ + private boolean mChatbotRoleSupported = false; /** List of supported extensions. */ private String[] mExts = new String[10]; /** Time used to compute when to query again. */ @@ -387,6 +400,104 @@ public class CapInfo implements Parcelable { this.mRcsIpVideoOnlyCallSupported = rcsIpVideoOnlyCallSupported; } + /** + * Checks whether Geo Push via SMS is supported. + */ + public boolean isGeoSmsSupported() { + return mGeoSmsSupported; + } + + /** + * Sets Geolocation Push via SMS as supported or not supported. + */ + public void setGeoSmsSupported(boolean geoSmsSupported) { + this.mGeoSmsSupported = geoSmsSupported; + } + + /** + * Checks whether RCS call composer is supported. + */ + public boolean isCallComposerSupported() { + return mCallComposerSupported; + } + + /** + * Sets call composer as supported or not supported. + */ + public void setCallComposerSupported(boolean callComposerSupported) { + this.mCallComposerSupported = callComposerSupported; + } + + /** + * Checks whether post call is supported. + */ + public boolean isPostCallSupported(){ + return mPostCallSupported; + } + + /** + * Sets post call as supported or not supported. + */ + public void setPostCallSupported(boolean postCallSupported) { + this.mPostCallSupported = postCallSupported; + } + + /** + * Checks whether shared map is supported. + */ + public boolean isSharedMapSupported() { + return mSharedMapSupported; + } + + /** + * Sets shared map as supported or not supported. + */ + public void setSharedMapSupported(boolean sharedMapSupported) { + this.mSharedMapSupported = sharedMapSupported; + } + + /** + * Checks whether shared sketch is supported. + */ + public boolean isSharedSketchSupported() { + return mSharedSketchSupported; + } + + /** + * Sets shared sketch as supported or not supported. + */ + public void setSharedSketchSupported(boolean sharedSketchSupported) { + this.mSharedSketchSupported = sharedSketchSupported; + } + + /** + * Checks whether chatbot communication is supported. + */ + public boolean isChatbotSupported() { + return mChatbotSupported; + } + + /** + * Sets chatbot communication as supported or not supported. + */ + public void setChatbotSupported(boolean chatbotSupported) { + this.mChatbotSupported = chatbotSupported; + } + + /** + * Checks whether chatbot role is supported. + */ + public boolean isChatbotRoleSupported() { + return mChatbotRoleSupported; + } + + /** + * Sets chatbot role as supported or not supported. + */ + public void setChatbotRoleSupported(boolean chatbotRoleSupported) { + this.mChatbotRoleSupported = chatbotRoleSupported; + } + /** Gets the list of supported extensions. */ public String[] getExts() { return mExts; @@ -435,6 +546,13 @@ public class CapInfo implements Parcelable { dest.writeInt(mGeoPushSupported ? 1 : 0); dest.writeInt(mSmSupported ? 1 : 0); dest.writeInt(mFullSnFGroupChatSupported ? 1 : 0); + dest.writeInt(mGeoSmsSupported ? 1 : 0); + dest.writeInt(mCallComposerSupported ? 1 : 0); + dest.writeInt(mPostCallSupported ? 1 : 0); + dest.writeInt(mSharedMapSupported ? 1 : 0); + dest.writeInt(mSharedSketchSupported ? 1 : 0); + dest.writeInt(mChatbotSupported ? 1 : 0); + dest.writeInt(mChatbotRoleSupported ? 1 : 0); dest.writeInt(mRcsIpVoiceCallSupported ? 1 : 0); dest.writeInt(mRcsIpVideoCallSupported ? 1 : 0); @@ -477,6 +595,13 @@ public class CapInfo implements Parcelable { mGeoPushSupported = (source.readInt() == 0) ? false : true; mSmSupported = (source.readInt() == 0) ? false : true; mFullSnFGroupChatSupported = (source.readInt() == 0) ? false : true; + mGeoSmsSupported = (source.readInt() == 0) ? false : true; + mCallComposerSupported = (source.readInt() == 0) ? false : true; + mPostCallSupported = (source.readInt() == 0) ? false : true; + mSharedMapSupported = (source.readInt() == 0) ? false : true; + mSharedSketchSupported = (source.readInt() == 0) ? false : true; + mChatbotSupported = (source.readInt() == 0) ? false : true; + mChatbotRoleSupported = (source.readInt() == 0) ? false : true; mRcsIpVoiceCallSupported = (source.readInt() == 0) ? false : true; mRcsIpVideoCallSupported = (source.readInt() == 0) ? false : true; diff --git a/core/java/com/android/ims/internal/uce/common/StatusCode.java b/core/java/com/android/ims/internal/uce/common/StatusCode.java index 7250eee70ecb..7f69493aa284 100644 --- a/core/java/com/android/ims/internal/uce/common/StatusCode.java +++ b/core/java/com/android/ims/internal/uce/common/StatusCode.java @@ -16,10 +16,9 @@ package com.android.ims.internal.uce.common; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; /** Class for UCE status codes. diff --git a/core/java/com/android/ims/internal/uce/common/UceLong.java b/core/java/com/android/ims/internal/uce/common/UceLong.java index 720789918e45..bf514471b506 100644 --- a/core/java/com/android/ims/internal/uce/common/UceLong.java +++ b/core/java/com/android/ims/internal/uce/common/UceLong.java @@ -16,10 +16,9 @@ package com.android.ims.internal.uce.common; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; /** Simple object wrapper for a long type. diff --git a/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java b/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java index bcb9f2d6284d..1da5a2439f02 100644 --- a/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java +++ b/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java @@ -15,11 +15,11 @@ */ package com.android.ims.internal.uce.options; -import android.annotation.UnsupportedAppUsage; -import com.android.ims.internal.uce.common.CapInfo; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; + +import com.android.ims.internal.uce.common.CapInfo; /** @hide */ public class OptionsCapInfo implements Parcelable { diff --git a/core/java/com/android/ims/internal/uce/options/OptionsCmdId.java b/core/java/com/android/ims/internal/uce/options/OptionsCmdId.java index 14c64ac105bb..401ca2fa24ea 100644 --- a/core/java/com/android/ims/internal/uce/options/OptionsCmdId.java +++ b/core/java/com/android/ims/internal/uce/options/OptionsCmdId.java @@ -17,7 +17,7 @@ package com.android.ims.internal.uce.options; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java b/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java index 4af3e6e3cea4..70a7a84d3820 100644 --- a/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java +++ b/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java @@ -16,13 +16,13 @@ package com.android.ims.internal.uce.options; -import com.android.ims.internal.uce.common.StatusCode; -import com.android.ims.internal.uce.common.CapInfo; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import com.android.ims.internal.uce.common.CapInfo; +import com.android.ims.internal.uce.common.StatusCode; + /** @hide */ public class OptionsCmdStatus implements Parcelable { diff --git a/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java index c5f333d35ba5..5afddf0c42c0 100644 --- a/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java +++ b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.options; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java b/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java index 745df5b71aa7..1a3a028713f6 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java +++ b/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java @@ -16,12 +16,12 @@ package com.android.ims.internal.uce.presence; -import com.android.ims.internal.uce.common.CapInfo; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import com.android.ims.internal.uce.common.CapInfo; + /** @hide */ public class PresCapInfo implements Parcelable { diff --git a/core/java/com/android/ims/internal/uce/presence/PresCmdId.java b/core/java/com/android/ims/internal/uce/presence/PresCmdId.java index 41020ec5b49b..fba0c77e8dbf 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresCmdId.java +++ b/core/java/com/android/ims/internal/uce/presence/PresCmdId.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java b/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java index ff8069c569ff..fbc64b83a360 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java +++ b/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java @@ -16,12 +16,12 @@ package com.android.ims.internal.uce.presence; -import com.android.ims.internal.uce.common.StatusCode; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import com.android.ims.internal.uce.common.StatusCode; + /** @hide */ public class PresCmdStatus implements Parcelable{ diff --git a/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java b/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java index 87193e36ce90..fdff86f9669f 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java +++ b/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -47,6 +47,10 @@ public class PresPublishTriggerType implements Parcelable { public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_IWLAN = 8; /** Trigger is unknown. */ public static final int UCE_PRES_PUBLISH_TRIGGER_UNKNOWN = 9; + /** Move to 5G NR with VoPS disabled. */ + public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; + /** Move to 5G NR with VoPS enabled. */ + public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; @@ -113,4 +117,4 @@ public class PresPublishTriggerType implements Parcelable { public void readFromParcel(Parcel source) { mPublishTriggerType = source.readInt(); } -}
\ No newline at end of file +} diff --git a/core/java/com/android/ims/internal/uce/presence/PresResInfo.java b/core/java/com/android/ims/internal/uce/presence/PresResInfo.java index 237c9994451a..af9b0568d29b 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresResInfo.java +++ b/core/java/com/android/ims/internal/uce/presence/PresResInfo.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java b/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java index 29699ea6c802..9f3725133452 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java +++ b/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java @@ -16,9 +16,10 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; + import java.util.Arrays; /** @hide */ diff --git a/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java b/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java index ab46e4b6295e..65b9fdbbeb18 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java +++ b/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/presence/PresServiceInfo.java b/core/java/com/android/ims/internal/uce/presence/PresServiceInfo.java index 83ba722fe2f1..5eafa0fde8cc 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresServiceInfo.java +++ b/core/java/com/android/ims/internal/uce/presence/PresServiceInfo.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java index 5e4259297d74..45b02f31eddc 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java +++ b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java b/core/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java index bee928c3280a..ab1e17c48e75 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java +++ b/core/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java b/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java index 7a47786b5af6..3608eb6a5e8a 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java +++ b/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java @@ -16,7 +16,7 @@ package com.android.ims.internal.uce.presence; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java index 4b0b098d4e5b..9aee879f21da 100644 --- a/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java +++ b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java @@ -18,16 +18,9 @@ package com.android.ims.internal.uce.uceservice; import android.content.Context; import android.content.Intent; - -import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; -import android.os.Message; -import android.os.ServiceManager; import android.os.RemoteException; - -import java.util.HashMap; -import android.util.Log; +import android.os.ServiceManager; /** * ImsUceManager Declaration @@ -49,55 +42,25 @@ public class ImsUceManager { private IUceService mUceService = null; private UceServiceDeathRecipient mDeathReceipient = new UceServiceDeathRecipient(); private Context mContext; - private int mPhoneId; - /** - * Stores the UceManager instaces of Clients identified by - * phoneId - * @hide - */ - private static HashMap<Integer, ImsUceManager> sUceManagerInstances = - new HashMap<Integer, ImsUceManager>(); + private static final Object sLock = new Object(); + private static ImsUceManager sUceManager; public static final String ACTION_UCE_SERVICE_UP = "com.android.ims.internal.uce.UCE_SERVICE_UP"; public static final String ACTION_UCE_SERVICE_DOWN = "com.android.ims.internal.uce.UCE_SERVICE_DOWN"; - /** Uce Service status received in IUceListener.setStatus() - * callback - * @hide - */ - public static final int UCE_SERVICE_STATUS_FAILURE = 0; - /** indicate UI to call Presence/Options API. */ - public static final int UCE_SERVICE_STATUS_ON = 1; - /** Indicate UI destroy Presence/Options */ - public static final int UCE_SERVICE_STATUS_CLOSED = 2; - /** Service up and trying to register for network events */ - public static final int UCE_SERVICE_STATUS_READY = 3; - - /** - * Part of the ACTION_UCE_SERVICE_UP or _DOWN intents. A long - * value; the phone ID corresponding to the IMS service coming up or down. - * Internal use only. - * @hide - */ - public static final String EXTRA_PHONE_ID = "android:phone_id"; - /** * Gets the instance of UCE Manager * @hide */ - public static ImsUceManager getInstance(Context context, int phoneId) { - //if (DBG) Log.d (LOG_TAG, "GetInstance Called"); - synchronized (sUceManagerInstances) { - if (sUceManagerInstances.containsKey(phoneId)) { - return sUceManagerInstances.get(phoneId); - } else { - ImsUceManager uceMgr = new ImsUceManager(context, phoneId); - sUceManagerInstances.put(phoneId, uceMgr); - return uceMgr; + public static ImsUceManager getInstance(Context context) { + synchronized (sLock) { + if (sUceManager == null && context != null) { + sUceManager = new ImsUceManager(context); } + return sUceManager; } } @@ -105,10 +68,9 @@ public class ImsUceManager { * Constructor * @hide */ - private ImsUceManager(Context context, int phoneId) { + private ImsUceManager(Context context) { //if (DBG) Log.d (LOG_TAG, "Constructor"); mContext = context; - mPhoneId = phoneId; createUceService(true); } @@ -129,7 +91,7 @@ public class ImsUceManager { * Gets the UCE service name * @hide */ - private String getUceServiceName(int phoneId) { + private String getUceServiceName() { return UCE_SERVICE; } @@ -143,14 +105,14 @@ public class ImsUceManager { public void createUceService(boolean checkService) { //if (DBG) Log.d (LOG_TAG, "CreateUceService Called"); if (checkService) { - IBinder binder = ServiceManager.checkService(getUceServiceName(mPhoneId)); + IBinder binder = ServiceManager.checkService(getUceServiceName()); if (binder == null) { //if (DBG)Log.d (LOG_TAG, "Unable to find IBinder"); return; } } - IBinder b = ServiceManager.getService(getUceServiceName(mPhoneId)); + IBinder b = ServiceManager.getService(getUceServiceName()); if (b != null) { try { @@ -174,12 +136,10 @@ public class ImsUceManager { private class UceServiceDeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { - //if (DBG) Log.d (LOG_TAG, "found IBinder/IUceService Service Died"); mUceService = null; if (mContext != null) { Intent intent = new Intent(ACTION_UCE_SERVICE_DOWN); - intent.putExtra(EXTRA_PHONE_ID, mPhoneId); mContext.sendBroadcast(new Intent(intent)); } } diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java index 7307de5146f8..cfbb273acf31 100644 --- a/core/java/com/android/internal/app/AlertActivity.java +++ b/core/java/com/android/internal/app/AlertActivity.java @@ -16,9 +16,9 @@ package com.android.internal.app; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.Dialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.DialogInterface; import android.os.Bundle; import android.view.KeyEvent; diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 3462e08a4c6a..a08bf9983924 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -18,14 +18,11 @@ package com.android.internal.app; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import com.android.internal.R; - import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.AlertDialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.DialogInterface; -import android.content.res.Configuration; import android.content.res.TypedArray; import android.database.Cursor; import android.graphics.drawable.Drawable; @@ -33,7 +30,6 @@ import android.os.Handler; import android.os.Message; import android.text.Layout; import android.text.TextUtils; -import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.util.AttributeSet; import android.util.TypedValue; @@ -46,7 +42,6 @@ import android.view.ViewGroup.LayoutParams; import android.view.ViewParent; import android.view.ViewStub; import android.view.Window; -import android.view.WindowInsets; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; @@ -63,6 +58,8 @@ import android.widget.ScrollView; import android.widget.SimpleCursorAdapter; import android.widget.TextView; +import com.android.internal.R; + import java.lang.ref.WeakReference; public class AlertController { diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java index f8483091ba21..22a25646c99d 100644 --- a/core/java/com/android/internal/app/AssistUtils.java +++ b/core/java/com/android/internal/app/AssistUtils.java @@ -17,7 +17,7 @@ package com.android.internal.app; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 102ba5c2ec5e..c0c9dd32a52a 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -26,7 +26,6 @@ import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.ActivityManager; import android.app.prediction.AppPredictionContext; @@ -34,6 +33,7 @@ import android.app.prediction.AppPredictionManager; import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipboardManager; import android.content.ComponentName; diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index a5f055f09562..9488e4f3b297 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -20,12 +20,12 @@ import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.ActivityTaskManager; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java index e3d07aaa8fe8..d418770e00bf 100644 --- a/core/java/com/android/internal/app/LocaleHelper.java +++ b/core/java/com/android/internal/app/LocaleHelper.java @@ -17,7 +17,7 @@ package com.android.internal.app; import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.icu.text.ListFormatter; import android.icu.util.ULocale; import android.os.LocaleList; diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java index 75174246cd99..3343593f2bc3 100644 --- a/core/java/com/android/internal/app/LocalePicker.java +++ b/core/java/com/android/internal/app/LocalePicker.java @@ -16,13 +16,11 @@ package com.android.internal.app; -import com.android.internal.R; - -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.IActivityManager; import android.app.ListFragment; import android.app.backup.BackupManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -38,11 +36,13 @@ import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; +import com.android.internal.R; + import java.text.Collator; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.ArrayList; public class LocalePicker extends ListFragment { private static final String TAG = "LocalePicker"; diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java index 49f77e11cf80..1c5ca593ebba 100644 --- a/core/java/com/android/internal/app/LocaleStore.java +++ b/core/java/com/android/internal/app/LocaleStore.java @@ -16,7 +16,7 @@ package com.android.internal.app; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.LocaleList; import android.provider.Settings; diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java index 9a802a9c0fa9..89aa770d7f1c 100644 --- a/core/java/com/android/internal/app/NetInitiatedActivity.java +++ b/core/java/com/android/internal/app/NetInitiatedActivity.java @@ -16,19 +16,19 @@ package com.android.internal.app; -import android.annotation.UnsupportedAppUsage; import android.app.AlertDialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.widget.Toast; import android.util.Log; -import android.location.LocationManager; +import android.widget.Toast; import com.android.internal.R; import com.android.internal.location.GpsNetInitiatedHandler; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 7d19eb6f54cd..871e4f84f3b6 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -21,7 +21,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.UiThread; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityTaskManager; @@ -29,6 +28,7 @@ import android.app.ActivityThread; import android.app.VoiceInteractor.PickOptionRequest; import android.app.VoiceInteractor.PickOptionRequest.Option; import android.app.VoiceInteractor.Prompt; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java index e71ee66c677c..0cd12022e17d 100644 --- a/core/java/com/android/internal/app/WindowDecorActionBar.java +++ b/core/java/com/android/internal/app/WindowDecorActionBar.java @@ -16,28 +16,17 @@ package com.android.internal.app; -import com.android.internal.R; -import com.android.internal.view.ActionBarPolicy; -import com.android.internal.view.menu.MenuBuilder; -import com.android.internal.view.menu.MenuPopupHelper; -import com.android.internal.view.menu.SubMenuBuilder; -import com.android.internal.widget.ActionBarContainer; -import com.android.internal.widget.ActionBarContextView; -import com.android.internal.widget.ActionBarOverlayLayout; -import com.android.internal.widget.DecorToolbar; -import com.android.internal.widget.ScrollingTabContainerView; - import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.annotation.UnsupportedAppUsage; import android.app.ActionBar; import android.app.Activity; import android.app.Dialog; import android.app.FragmentTransaction; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -58,6 +47,17 @@ import android.view.animation.AnimationUtils; import android.widget.SpinnerAdapter; import android.widget.Toolbar; +import com.android.internal.R; +import com.android.internal.view.ActionBarPolicy; +import com.android.internal.view.menu.MenuBuilder; +import com.android.internal.view.menu.MenuPopupHelper; +import com.android.internal.view.menu.SubMenuBuilder; +import com.android.internal.widget.ActionBarContainer; +import com.android.internal.widget.ActionBarContextView; +import com.android.internal.widget.ActionBarOverlayLayout; +import com.android.internal.widget.DecorToolbar; +import com.android.internal.widget.ScrollingTabContainerView; + import java.lang.ref.WeakReference; import java.util.ArrayList; diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java new file mode 100644 index 000000000000..0b937fad7df1 --- /dev/null +++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java @@ -0,0 +1,34 @@ +/* + * 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 com.android.internal.compat; + +import android.os.Build; + +/** + * Platform private class for determining the type of Android build installed. + * + */ +public class AndroidBuildClassifier { + + public boolean isDebuggableBuild() { + return Build.IS_DEBUGGABLE; + } + + public boolean isFinalBuild() { + return "REL".equals(Build.VERSION.CODENAME); + } +} diff --git a/core/java/com/android/internal/compat/IOverrideValidator.aidl b/core/java/com/android/internal/compat/IOverrideValidator.aidl new file mode 100644 index 000000000000..add4708863aa --- /dev/null +++ b/core/java/com/android/internal/compat/IOverrideValidator.aidl @@ -0,0 +1,38 @@ +/* + * 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 com.android.internal.compat; + +import android.content.pm.ApplicationInfo; + +import com.android.internal.compat.OverrideAllowedState; + +/** + * Platform private API for determining whether a changeId can be overridden. + * + * {@hide} + */ +interface IOverrideValidator +{ + /** + * Validation function. + * @param changeId id of the change to be toggled on or off. + * @param packageName package of the app for which the change should be overridden. + * @return {@link OverrideAllowedState} specifying whether the change can be overridden for + * the given package or a reason why not. + */ + OverrideAllowedState getOverrideAllowedState(long changeId, String packageName); +} diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index 7dcb12c9e72b..4c203d394759 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -17,6 +17,7 @@ package com.android.internal.compat; import android.content.pm.ApplicationInfo; +import com.android.internal.compat.IOverrideValidator; import java.util.Map; parcelable CompatibilityChangeConfig; @@ -195,4 +196,9 @@ interface IPlatformCompat * @return An array of {@link CompatChangeInfo} known to the service. */ CompatibilityChangeInfo[] listAllChanges(); + + /** + * Get an instance that can determine whether a changeid can be overridden for a package name. + */ + IOverrideValidator getOverrideValidator(); } diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.aidl b/core/java/com/android/internal/compat/OverrideAllowedState.aidl new file mode 100644 index 000000000000..10ceac786841 --- /dev/null +++ b/core/java/com/android/internal/compat/OverrideAllowedState.aidl @@ -0,0 +1,19 @@ +/* + * 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 com.android.internal.compat; + +parcelable OverrideAllowedState;
\ No newline at end of file diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java new file mode 100644 index 000000000000..56216c251070 --- /dev/null +++ b/core/java/com/android/internal/compat/OverrideAllowedState.java @@ -0,0 +1,153 @@ +/* + * 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 com.android.internal.compat; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This class contains all the possible override allowed states. + */ +public final class OverrideAllowedState implements Parcelable { + @IntDef({ + ALLOWED, + DISABLED_NOT_DEBUGGABLE, + DISABLED_NON_TARGET_SDK, + DISABLED_TARGET_SDK_TOO_HIGH, + PACKAGE_DOES_NOT_EXIST + }) + @Retention(RetentionPolicy.SOURCE) + public @interface State { + } + + /** + * Change can be overridden. + */ + public static final int ALLOWED = 0; + /** + * Change cannot be overridden, due to the app not being debuggable. + */ + public static final int DISABLED_NOT_DEBUGGABLE = 1; + /** + * Change cannot be overridden, due to the build being non-debuggable and the change being + * non-targetSdk. + */ + public static final int DISABLED_NON_TARGET_SDK = 2; + /** + * Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk. + */ + public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3; + /** + * Package does not exist. + */ + public static final int PACKAGE_DOES_NOT_EXIST = 4; + + @State + public final int state; + public final int appTargetSdk; + public final int changeIdTargetSdk; + + private OverrideAllowedState(Parcel parcel) { + state = parcel.readInt(); + appTargetSdk = parcel.readInt(); + changeIdTargetSdk = parcel.readInt(); + } + + public OverrideAllowedState(@State int state, int appTargetSdk, int changeIdTargetSdk) { + this.state = state; + this.appTargetSdk = appTargetSdk; + this.changeIdTargetSdk = changeIdTargetSdk; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(state); + out.writeInt(appTargetSdk); + out.writeInt(changeIdTargetSdk); + } + + /** + * Enforces the policy for overriding compat changes. + * + * @param changeId the change id that was attempted to be overridden. + * @param packageName the package for which the attempt was made. + * @throws SecurityException if the policy forbids this operation. + */ + public void enforce(long changeId, String packageName) + throws SecurityException { + switch (state) { + case ALLOWED: + return; + case DISABLED_NOT_DEBUGGABLE: + throw new SecurityException( + "Cannot override a change on a non-debuggable app and user build."); + case DISABLED_NON_TARGET_SDK: + throw new SecurityException( + "Cannot override a default enabled/disabled change on a user build."); + case DISABLED_TARGET_SDK_TOO_HIGH: + throw new SecurityException(String.format( + "Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is " + + "above the change's targetSdk threshold (%4$d)", + changeId, packageName, appTargetSdk, changeIdTargetSdk)); + case PACKAGE_DOES_NOT_EXIST: + throw new SecurityException(String.format( + "Cannot override %1$d for %2$s because the package does not exist, and " + + "the change is targetSdk gated.", + changeId, packageName)); + } + } + + public static final @NonNull + Parcelable.Creator<OverrideAllowedState> CREATOR = + new Parcelable.Creator<OverrideAllowedState>() { + public OverrideAllowedState createFromParcel(Parcel parcel) { + OverrideAllowedState info = new OverrideAllowedState(parcel); + return info; + } + + public OverrideAllowedState[] newArray(int size) { + return new OverrideAllowedState[size]; + } + }; + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof OverrideAllowedState)) { + return false; + } + OverrideAllowedState otherState = (OverrideAllowedState) obj; + return state == otherState.state + && appTargetSdk == otherState.appTargetSdk + && changeIdTargetSdk == otherState.changeIdTargetSdk; + } +} diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java index 5d7d3af8750a..9baa6fbb9217 100644 --- a/core/java/com/android/internal/content/PackageMonitor.java +++ b/core/java/com/android/internal/content/PackageMonitor.java @@ -16,8 +16,8 @@ package com.android.internal.content; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; diff --git a/core/java/com/android/internal/content/ReferrerIntent.java b/core/java/com/android/internal/content/ReferrerIntent.java index 6d05f7e72a7a..6af03dd29899 100644 --- a/core/java/com/android/internal/content/ReferrerIntent.java +++ b/core/java/com/android/internal/content/ReferrerIntent.java @@ -16,7 +16,7 @@ package com.android.internal.content; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Parcel; diff --git a/core/java/com/android/internal/database/SortCursor.java b/core/java/com/android/internal/database/SortCursor.java index 7fe809ee319b..230a9b87727a 100644 --- a/core/java/com/android/internal/database/SortCursor.java +++ b/core/java/com/android/internal/database/SortCursor.java @@ -16,7 +16,7 @@ package com.android.internal.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.AbstractCursor; import android.database.Cursor; import android.database.DataSetObserver; diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index f916cf64564d..ed04fd83a515 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -15,7 +15,7 @@ */ package com.android.internal.logging; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.metrics.LogMaker; import android.os.Build; diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java index 2ad9759b1f68..4eb7dede7769 100644 --- a/core/java/com/android/internal/net/LegacyVpnInfo.java +++ b/core/java/com/android/internal/net/LegacyVpnInfo.java @@ -16,8 +16,8 @@ package com.android.internal.net; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.net.NetworkInfo; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index e6be54964705..f5a19fe73a86 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -16,8 +16,8 @@ package com.android.internal.net; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java index 940cc363f742..4bb012aac769 100644 --- a/core/java/com/android/internal/net/VpnProfile.java +++ b/core/java/com/android/internal/net/VpnProfile.java @@ -16,10 +16,9 @@ package com.android.internal.net; -import android.annotation.UnsupportedAppUsage; -import android.os.Build; +import android.compat.annotation.UnsupportedAppUsage; import android.net.ProxyInfo; -import android.net.Uri; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/com/android/internal/os/AndroidPrintStream.java b/core/java/com/android/internal/os/AndroidPrintStream.java index fe2341144d28..a6e41ff02d12 100644 --- a/core/java/com/android/internal/os/AndroidPrintStream.java +++ b/core/java/com/android/internal/os/AndroidPrintStream.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; /** diff --git a/core/java/com/android/internal/os/AtomicFile.java b/core/java/com/android/internal/os/AtomicFile.java index a72a2f5e1be3..80b3314bf3d3 100644 --- a/core/java/com/android/internal/os/AtomicFile.java +++ b/core/java/com/android/internal/os/AtomicFile.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.FileUtils; import android.util.Log; diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java index 5ba662913529..db87f51cf6db 100644 --- a/core/java/com/android/internal/os/BaseCommand.java +++ b/core/java/com/android/internal/os/BaseCommand.java @@ -17,7 +17,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ShellCommand; import java.io.PrintStream; diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index b1fc369835c6..b3ea118d9c73 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -15,7 +15,7 @@ */ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.BatteryStats.Uid; import java.util.List; diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index e85508ed7891..b131ab83cc79 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 3bd0fd29c3f9..183c0fb70e27 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -18,10 +18,10 @@ package com.android.internal.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.UidTraffic; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java index 4901e1f67d92..95c36ca8429e 100644 --- a/core/java/com/android/internal/os/BinderInternal.java +++ b/core/java/com/android/internal/os/BinderInternal.java @@ -17,7 +17,7 @@ package com.android.internal.os; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Handler; import android.os.IBinder; diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java index d32349834dd8..a18943c264f5 100644 --- a/core/java/com/android/internal/os/ClassLoaderFactory.java +++ b/core/java/com/android/internal/os/ClassLoaderFactory.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Trace; import dalvik.system.DelegateLastClassLoader; diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java index d08930b007ff..f8f9fa9d0e70 100644 --- a/core/java/com/android/internal/os/FuseAppLoop.java +++ b/core/java/com/android/internal/os/FuseAppLoop.java @@ -18,17 +18,19 @@ package com.android.internal.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; -import android.os.ProxyFileDescriptorCallback; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.os.ProxyFileDescriptorCallback; import android.system.ErrnoException; import android.system.OsConstants; import android.util.Log; import android.util.SparseArray; + import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; + import java.util.HashMap; import java.util.LinkedList; import java.util.Map; diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java index c8bfa1b02e22..a11c815a94bc 100644 --- a/core/java/com/android/internal/os/HandlerCaller.java +++ b/core/java/com/android/internal/os/HandlerCaller.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; import android.os.Looper; diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index 8338d78af3a1..d3fe582ab4bd 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -17,7 +17,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java index dcf8d285eca9..f7b77422cdce 100644 --- a/core/java/com/android/internal/os/ProcessCpuTracker.java +++ b/core/java/com/android/internal/os/ProcessCpuTracker.java @@ -16,9 +16,14 @@ package com.android.internal.os; -import static android.os.Process.*; - -import android.annotation.UnsupportedAppUsage; +import static android.os.Process.PROC_COMBINE; +import static android.os.Process.PROC_OUT_FLOAT; +import static android.os.Process.PROC_OUT_LONG; +import static android.os.Process.PROC_OUT_STRING; +import static android.os.Process.PROC_PARENS; +import static android.os.Process.PROC_SPACE_TERM; + +import android.compat.annotation.UnsupportedAppUsage; import android.os.Process; import android.os.StrictMode; import android.os.SystemClock; diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index fa823c4bf2f6..13d0c5c831b6 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -16,10 +16,10 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ApplicationErrorReport; +import android.compat.annotation.UnsupportedAppUsage; import android.content.type.DefaultMimeMapFactory; import android.os.Build; import android.os.DeadObjectException; @@ -35,6 +35,7 @@ import com.android.internal.logging.AndroidConfig; import com.android.server.NetworkManagementSocketTagger; import dalvik.system.RuntimeHooks; +import dalvik.system.ThreadPrioritySetter; import dalvik.system.VMRuntime; import libcore.content.type.MimeMap; @@ -204,6 +205,7 @@ public class RuntimeInit { */ public static void preForkInit() { if (DEBUG) Slog.d(TAG, "Entered preForkInit."); + RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter()); RuntimeInit.enableDdms(); // TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e. // MimeMap.setDefault(DefaultMimeMapFactory.create()); @@ -216,6 +218,35 @@ public class RuntimeInit { MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create); } + private static class RuntimeThreadPrioritySetter implements ThreadPrioritySetter { + // Should remain consistent with kNiceValues[] in system/libartpalette/palette_android.cc + private static final int[] NICE_VALUES = { + Process.THREAD_PRIORITY_LOWEST, // 1 (MIN_PRIORITY) + Process.THREAD_PRIORITY_BACKGROUND + 6, + Process.THREAD_PRIORITY_BACKGROUND + 3, + Process.THREAD_PRIORITY_BACKGROUND, + Process.THREAD_PRIORITY_DEFAULT, // 5 (NORM_PRIORITY) + Process.THREAD_PRIORITY_DEFAULT - 2, + Process.THREAD_PRIORITY_DEFAULT - 4, + Process.THREAD_PRIORITY_URGENT_DISPLAY + 3, + Process.THREAD_PRIORITY_URGENT_DISPLAY + 2, + Process.THREAD_PRIORITY_URGENT_DISPLAY // 10 (MAX_PRIORITY) + }; + + @Override + public void setPriority(int nativeTid, int priority) { + // Check NICE_VALUES[] length first. + if (NICE_VALUES.length != (1 + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY)) { + throw new AssertionError("Unexpected NICE_VALUES.length=" + NICE_VALUES.length); + } + // Priority should be in the range of MIN_PRIORITY (1) to MAX_PRIORITY (10). + if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { + throw new IllegalArgumentException("Priority out of range: " + priority); + } + Process.setThreadPriority(nativeTid, NICE_VALUES[priority - Thread.MIN_PRIORITY]); + } + } + @UnsupportedAppUsage protected static final void commonInit() { if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java index d78bfac1f878..003f61079dcf 100644 --- a/core/java/com/android/internal/os/SomeArgs.java +++ b/core/java/com/android/internal/os/SomeArgs.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Helper class for passing more arguments though a message diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 33adec106d97..c1c74dcfb9e6 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -35,6 +35,7 @@ import android.system.ErrnoException; import android.system.Os; import android.util.Log; +import dalvik.annotation.optimization.FastNative; import dalvik.system.ZygoteHooks; import libcore.io.IoUtils; @@ -49,9 +50,9 @@ import java.io.InputStreamReader; /** @hide */ public final class Zygote { /* - * Bit values for "runtimeFlags" argument. The definitions are duplicated - * in the native code. - */ + * Bit values for "runtimeFlags" argument. The definitions are duplicated + * in the native code. + */ /** enable debugging over JDWP */ public static final int DEBUG_ENABLE_JDWP = 1; @@ -187,6 +188,11 @@ public final class Zygote { */ public static final int SOCKET_BUFFER_SIZE = 256; + /** + * @hide for internal use only + */ + private static final int PRIORITY_MAX = -20; + /** a prototype instance for a future List.toArray() */ protected static final int[][] INT_ARRAY_2D = new int[0][0]; @@ -251,8 +257,7 @@ public final class Zygote { int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, int targetSdkVersion) { ZygoteHooks.preFork(); - // Resets nice priority for zygote process. - resetNicePriority(); + int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir); @@ -264,6 +269,10 @@ public final class Zygote { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); } + + // Set the Java Language thread priority to the default value for new apps. + Thread.currentThread().setPriority(Thread.NORM_PRIORITY); + ZygoteHooks.postForkCommon(); return pid; } @@ -298,7 +307,7 @@ public final class Zygote { int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir) { nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, - niceName, startChildZygote, instructionSet, appDataDir); + niceName, startChildZygote, instructionSet, appDataDir); // Enable tracing as soon as possible for the child process. Trace.setTracingEnabled(true, runtimeFlags); @@ -306,6 +315,9 @@ public final class Zygote { // Note that this event ends at the end of handleChildProc. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); + // Set the Java Language thread priority to the default value for new apps. + Thread.currentThread().setPriority(Thread.NORM_PRIORITY); + /* * This is called here (instead of after the fork but before the specialize) to maintain * consistancy with the code paths for forkAndSpecialize. @@ -350,15 +362,19 @@ public final class Zygote { public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { ZygoteHooks.preFork(); - // Resets nice priority for zygote process. - resetNicePriority(); + int pid = nativeForkSystemServer( uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities); + // Enable tracing as soon as we enter the system_server. if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); } + + // Set the Java Language thread priority to the default value for new apps. + Thread.currentThread().setPriority(Thread.NORM_PRIORITY); + ZygoteHooks.postForkCommon(); return pid; } @@ -476,13 +492,16 @@ public final class Zygote { /** * Fork a new unspecialized app process from the zygote * + * @param usapPoolSocket The server socket the USAP will call accept on * @param sessionSocketRawFDs Anonymous session sockets that are currently open + * @param isPriorityFork Value controlling the process priority level until accept is called * @return In the Zygote process this function will always return null; in unspecialized app * processes this function will return a Runnable object representing the new * application that is passed up from usapMain. */ static Runnable forkUsap(LocalServerSocket usapPoolSocket, - int[] sessionSocketRawFDs) { + int[] sessionSocketRawFDs, + boolean isPriorityFork) { FileDescriptor[] pipeFDs = null; try { @@ -492,7 +511,8 @@ public final class Zygote { } int pid = - nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs); + nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), + sessionSocketRawFDs, isPriorityFork); if (pid == 0) { IoUtils.closeQuietly(pipeFDs[0]); @@ -506,8 +526,9 @@ public final class Zygote { } private static native int nativeForkUsap(int readPipeFD, - int writePipeFD, - int[] sessionSocketRawFDs); + int writePipeFD, + int[] sessionSocketRawFDs, + boolean isPriorityFork); /** * This function is used by unspecialized app processes to wait for specialization requests from @@ -518,7 +539,7 @@ public final class Zygote { * @return A runnable oject representing the new application. */ private static Runnable usapMain(LocalServerSocket usapPoolSocket, - FileDescriptor writePipe) { + FileDescriptor writePipe) { final int pid = Process.myPid(); Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32"); @@ -527,6 +548,11 @@ public final class Zygote { Credentials peerCredentials = null; ZygoteArguments args = null; + // Change the priority to max before calling accept so we can respond to new specialization + // requests as quickly as possible. This will be reverted to the default priority in the + // native specialization code. + boostUsapPriority(); + while (true) { try { sessionSocket = usapPoolSocket.accept(); @@ -568,6 +594,7 @@ public final class Zygote { try { // SIGTERM is blocked on loop exit. This prevents a USAP that is specializing from // being killed during a pool flush. + setAppProcessName(args, "USAP"); applyUidSecurityPolicy(args, peerCredentials); applyDebuggerSystemProperty(args); @@ -628,23 +655,18 @@ public final class Zygote { } specializeAppProcess(args.mUid, args.mGid, args.mGids, - args.mRuntimeFlags, rlimits, args.mMountExternal, - args.mSeInfo, args.mNiceName, args.mStartChildZygote, - args.mInstructionSet, args.mAppDataDir); + args.mRuntimeFlags, rlimits, args.mMountExternal, + args.mSeInfo, args.mNiceName, args.mStartChildZygote, + args.mInstructionSet, args.mAppDataDir); disableExecuteOnly(args.mTargetSdkVersion); - if (args.mNiceName != null) { - Process.setArgV0(args.mNiceName); - } - - // End of the postFork event. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return ZygoteInit.zygoteInit(args.mTargetSdkVersion, - args.mDisabledCompatChanges, - args.mRemainingArgs, - null /* classLoader */); + args.mDisabledCompatChanges, + args.mRemainingArgs, + null /* classLoader */); } finally { // Unblock SIGTERM to restore the process to default behavior. unblockSigTerm(); @@ -663,6 +685,22 @@ public final class Zygote { private static native void nativeUnblockSigTerm(); + private static void boostUsapPriority() { + nativeBoostUsapPriority(); + } + + private static native void nativeBoostUsapPriority(); + + static void setAppProcessName(ZygoteArguments args, String loggingTag) { + if (args.mNiceName != null) { + Process.setArgV0(args.mNiceName); + } else if (args.mPackageName != null) { + Process.setArgV0(args.mPackageName); + } else { + Log.w(loggingTag, "Unable to set package name."); + } + } + private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: "; /** @@ -685,7 +723,7 @@ public final class Zygote { throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--start-child-zygote"); } else if (args.mApiBlacklistExemptions != null) { throw new IllegalArgumentException( - USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions"); + USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions"); } else if (args.mHiddenApiAccessLogSampleRate != -1) { throw new IllegalArgumentException( USAP_ERROR_PREFIX + "--hidden-api-log-sampling-rate="); @@ -696,8 +734,8 @@ public final class Zygote { throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--invoke-with"); } else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) { throw new ZygoteSecurityException("Client may not specify capabilities: " - + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities) - + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities)); + + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities) + + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities)); } } @@ -754,7 +792,7 @@ public final class Zygote { if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) { throw new ZygoteSecurityException( "System UID may not launch process with UID < " - + Process.SYSTEM_UID); + + Process.SYSTEM_UID); } } @@ -804,8 +842,8 @@ public final class Zygote { if (args.mInvokeWith != null && peerUid != 0 && (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) { throw new ZygoteSecurityException("Peer is permitted to specify an " - + "explicit invoke-with wrapper command only for debuggable " - + "applications."); + + "explicit invoke-with wrapper command only for debuggable " + + "applications."); } } @@ -888,7 +926,7 @@ public final class Zygote { return new LocalServerSocket(fd); } catch (IOException ex) { throw new RuntimeException( - "Error building socket from file descriptor: " + fileDesc, ex); + "Error building socket from file descriptor: " + fileDesc, ex); } } @@ -903,15 +941,6 @@ public final class Zygote { } /** - * Resets the calling thread priority to the default value (Thread.NORM_PRIORITY - * or nice value 0). This updates both the priority value in java.lang.Thread and - * the nice value (setpriority). - */ - static void resetNicePriority() { - Thread.currentThread().setPriority(Thread.NORM_PRIORITY); - } - - /** * Executes "/system/bin/sh -c <command>" using the exec() system call. * This method throws a runtime exception if exec() failed, otherwise, this * method never returns. @@ -941,4 +970,19 @@ public final class Zygote { command.append(" '").append(arg.replace("'", "'\\''")).append("'"); } } + + /** + * Parse the given unsolicited zygote message as type SIGCHLD, + * extract the payload information into the given output buffer. + * + * @param in The unsolicited zygote message to be parsed + * @param length The number of bytes in the message + * @param out The output buffer where the payload information will be placed + * @return Number of elements being place into output buffer, or -1 if + * either the message is malformed or not the type as expected here. + * + * @hide + */ + @FastNative + public static native int nativeParseSigChld(byte[] in, int length, int[] out); } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 4c37591d4a66..2666d5278a90 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -23,7 +23,7 @@ import static android.system.OsConstants.POLLIN; import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS; import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ApplicationInfo; import android.net.Credentials; import android.net.LocalSocket; @@ -346,7 +346,7 @@ class ZygoteConnection { if (zygoteServer.isUsapPoolEnabled()) { Runnable fpResult = zygoteServer.fillUsapPool( - new int[]{mSocket.getFileDescriptor().getInt$()}); + new int[]{mSocket.getFileDescriptor().getInt$()}, false); if (fpResult != null) { zygoteServer.setForkChild(); @@ -485,9 +485,7 @@ class ZygoteConnection { closeSocket(); - if (parsedArgs.mNiceName != null) { - Process.setArgV0(parsedArgs.mNiceName); - } + Zygote.setAppProcessName(parsedArgs, TAG); // End of the postFork event. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 7b77a92e3d3a..348262e1a9d3 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -19,8 +19,8 @@ package com.android.internal.os; import static android.system.OsConstants.S_IRWXG; import static android.system.OsConstants.S_IRWXO; -import android.annotation.UnsupportedAppUsage; import android.app.ApplicationLoaders; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.SharedLibraryInfo; import android.content.res.Resources; import android.content.res.TypedArray; @@ -825,6 +825,18 @@ public class ZygoteInit { return result; } + /** + * This is the entry point for a Zygote process. It creates the Zygote server, loads resources, + * and handles other tasks related to preparing the process for forking into applications. + * + * This process is started with a nice value of -20 (highest priority). All paths that flow + * into new processes are required to either set the priority to the default value or terminate + * before executing any non-system code. The native side of this occurs in SpecializeCommon, + * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess, + * ZygoteConnection.handleChildProc, and Zygote.usapMain. + * + * @param argv Command line arguments used to specify the Zygote's configuration. + */ @UnsupportedAppUsage public static void main(String argv[]) { ZygoteServer zygoteServer = null; @@ -888,8 +900,6 @@ public class ZygoteInit { EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload - } else { - Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup diff --git a/core/java/com/android/internal/os/ZygoteSecurityException.java b/core/java/com/android/internal/os/ZygoteSecurityException.java index 7e50cb885324..8111483b4a0f 100644 --- a/core/java/com/android/internal/os/ZygoteSecurityException.java +++ b/core/java/com/android/internal/os/ZygoteSecurityException.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Exception thrown when a security policy is violated. diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java index 1fd6e269348f..8d281b7ce9a0 100644 --- a/core/java/com/android/internal/os/ZygoteServer.java +++ b/core/java/com/android/internal/os/ZygoteServer.java @@ -66,6 +66,12 @@ class ZygoteServer { /** The default value used for the USAP_POOL_SIZE_MIN device property */ private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1"; + /** The default value used for the USAP_REFILL_DELAY_MS device property */ + private static final String USAP_POOL_REFILL_DELAY_MS_DEFAULT = "3000"; + + /** The "not a timestamp" value for the refill delay timestamp mechanism. */ + private static final int INVALID_TIMESTAMP = -1; + /** * Indicates if this Zygote server can support a unspecialized app process pool. Currently this * should only be true for the primary and secondary Zygotes, and not the App Zygotes or the @@ -131,6 +137,24 @@ class ZygoteServer { */ private int mUsapPoolRefillThreshold = 0; + /** + * Number of milliseconds to delay before refilling the pool if it hasn't reached its + * minimum value. + */ + private int mUsapPoolRefillDelayMs = -1; + + /** + * If and when we should refill the USAP pool. + */ + private UsapPoolRefillAction mUsapPoolRefillAction; + private long mUsapPoolRefillTriggerTimestamp; + + private enum UsapPoolRefillAction { + DELAYED, + IMMEDIATE, + NONE + } + ZygoteServer() { mUsapPoolEventFD = null; mZygoteSocket = null; @@ -160,9 +184,8 @@ class ZygoteServer { Zygote.USAP_POOL_SECONDARY_SOCKET_NAME); } - fetchUsapPoolPolicyProps(); - mUsapPoolSupported = true; + fetchUsapPoolPolicyProps(); } void setForkChild() { @@ -267,6 +290,13 @@ class ZygoteServer { mUsapPoolSizeMax); } + final String usapPoolRefillDelayMsPropString = Zygote.getConfigurationProperty( + ZygoteConfig.USAP_POOL_REFILL_DELAY_MS, USAP_POOL_REFILL_DELAY_MS_DEFAULT); + + if (!usapPoolRefillDelayMsPropString.isEmpty()) { + mUsapPoolRefillDelayMs = Integer.parseInt(usapPoolRefillDelayMsPropString); + } + // Sanity check if (mUsapPoolSizeMin >= mUsapPoolSizeMax) { Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size." @@ -293,9 +323,16 @@ class ZygoteServer { } } + private void fetchUsapPoolPolicyPropsIfUnfetched() { + if (mIsFirstPropertyCheck) { + mIsFirstPropertyCheck = false; + fetchUsapPoolPolicyProps(); + } + } + /** - * Checks to see if the current policy says that pool should be refilled, and spawns new USAPs - * if necessary. + * Refill the USAP Pool to the appropriate level, determined by whether this is a priority + * refill event or not. * * @param sessionSocketRawFDs Anonymous session sockets that are currently open * @return In the Zygote process this function will always return null; in unspecialized app @@ -303,38 +340,47 @@ class ZygoteServer { * application that is passed up from usapMain. */ - Runnable fillUsapPool(int[] sessionSocketRawFDs) { + Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool"); // Ensure that the pool properties have been fetched. - fetchUsapPoolPolicyPropsWithMinInterval(); + fetchUsapPoolPolicyPropsIfUnfetched(); int usapPoolCount = Zygote.getUsapPoolCount(); - int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; + int numUsapsToSpawn; + + if (isPriorityRefill) { + // Refill to min + numUsapsToSpawn = mUsapPoolSizeMin - usapPoolCount; + + Log.i("zygote", + "Priority USAP Pool refill. New USAPs: " + numUsapsToSpawn); + } else { + // Refill up to max + numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; - if (usapPoolCount < mUsapPoolSizeMin - || numUsapsToSpawn >= mUsapPoolRefillThreshold) { + Log.i("zygote", + "Delayed USAP Pool refill. New USAPs: " + numUsapsToSpawn); + } - // Disable some VM functionality and reset some system values - // before forking. - ZygoteHooks.preFork(); - Zygote.resetNicePriority(); + // Disable some VM functionality and reset some system values + // before forking. + ZygoteHooks.preFork(); - while (usapPoolCount++ < mUsapPoolSizeMax) { - Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs); + while (--numUsapsToSpawn >= 0) { + Runnable caller = + Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs, isPriorityRefill); - if (caller != null) { - return caller; - } + if (caller != null) { + return caller; } + } - // Re-enable runtime services for the Zygote. Services for unspecialized app process - // are re-enabled in specializeAppProcess. - ZygoteHooks.postForkCommon(); + // Re-enable runtime services for the Zygote. Services for unspecialized app process + // are re-enabled in specializeAppProcess. + ZygoteHooks.postForkCommon(); - Log.i("zygote", - "Filled the USAP pool. New USAPs: " + numUsapsToSpawn); - } + resetUsapRefillState(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -358,13 +404,18 @@ class ZygoteServer { mUsapPoolEnabled = newStatus; if (newStatus) { - return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }); + return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }, false); } else { Zygote.emptyUsapPool(); return null; } } + void resetUsapRefillState() { + mUsapPoolRefillAction = UsapPoolRefillAction.NONE; + mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; + } + /** * Runs the zygote process's select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request's @@ -377,8 +428,11 @@ class ZygoteServer { socketFDs.add(mZygoteSocket.getFileDescriptor()); peers.add(null); + mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; + while (true) { fetchUsapPoolPolicyPropsWithMinInterval(); + mUsapPoolRefillAction = UsapPoolRefillAction.NONE; int[] usapPipeFDs = null; StructPollfd[] pollFDs; @@ -430,140 +484,199 @@ class ZygoteServer { } } + int pollTimeoutMs; + + if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) { + pollTimeoutMs = -1; + } else { + long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp; + + if (elapsedTimeMs >= mUsapPoolRefillDelayMs) { + // Normalize the poll timeout value when the time between one poll event and the + // next pushes us over the delay value. This prevents poll receiving a 0 + // timeout value, which would result in it returning immediately. + pollTimeoutMs = -1; + + } else if (elapsedTimeMs <= 0) { + // This can occur if the clock used by currentTimeMillis is reset, which is + // possible because it is not guaranteed to be monotonic. Because we can't tell + // how far back the clock was set the best way to recover is to simply re-start + // the respawn delay countdown. + pollTimeoutMs = mUsapPoolRefillDelayMs; + + } else { + pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs); + } + } + + int pollReturnValue; try { - Os.poll(pollFDs, -1); + pollReturnValue = Os.poll(pollFDs, pollTimeoutMs); } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } - boolean usapPoolFDRead = false; - - while (--pollIndex >= 0) { - if ((pollFDs[pollIndex].revents & POLLIN) == 0) { - continue; - } - - if (pollIndex == 0) { - // Zygote server socket + if (pollReturnValue == 0) { + // The poll timeout has been exceeded. This only occurs when we have finished the + // USAP pool refill delay period. - ZygoteConnection newPeer = acceptCommandPeer(abiList); - peers.add(newPeer); - socketFDs.add(newPeer.getFileDescriptor()); + mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; + mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED; - } else if (pollIndex < usapPoolEventFDIndex) { - // Session socket accepted from the Zygote server socket + } else { + boolean usapPoolFDRead = false; - try { - ZygoteConnection connection = peers.get(pollIndex); - final Runnable command = connection.processOneCommand(this); + while (--pollIndex >= 0) { + if ((pollFDs[pollIndex].revents & POLLIN) == 0) { + continue; + } - // TODO (chriswailes): Is this extra check necessary? - if (mIsForkChild) { - // We're in the child. We should always have a command to run at this - // stage if processOneCommand hasn't called "exec". - if (command == null) { - throw new IllegalStateException("command == null"); + if (pollIndex == 0) { + // Zygote server socket + + ZygoteConnection newPeer = acceptCommandPeer(abiList); + peers.add(newPeer); + socketFDs.add(newPeer.getFileDescriptor()); + + } else if (pollIndex < usapPoolEventFDIndex) { + // Session socket accepted from the Zygote server socket + + try { + ZygoteConnection connection = peers.get(pollIndex); + final Runnable command = connection.processOneCommand(this); + + // TODO (chriswailes): Is this extra check necessary? + if (mIsForkChild) { + // We're in the child. We should always have a command to run at + // this stage if processOneCommand hasn't called "exec". + if (command == null) { + throw new IllegalStateException("command == null"); + } + + return command; + } else { + // We're in the server - we should never have any commands to run. + if (command != null) { + throw new IllegalStateException("command != null"); + } + + // We don't know whether the remote side of the socket was closed or + // not until we attempt to read from it from processOneCommand. This + // shows up as a regular POLLIN event in our regular processing + // loop. + if (connection.isClosedByPeer()) { + connection.closeSocket(); + peers.remove(pollIndex); + socketFDs.remove(pollIndex); + } } + } catch (Exception e) { + if (!mIsForkChild) { + // We're in the server so any exception here is one that has taken + // place pre-fork while processing commands or reading / writing + // from the control socket. Make a loud noise about any such + // exceptions so that we know exactly what failed and why. - return command; - } else { - // We're in the server - we should never have any commands to run. - if (command != null) { - throw new IllegalStateException("command != null"); - } + Slog.e(TAG, "Exception executing zygote command: ", e); + + // Make sure the socket is closed so that the other end knows + // immediately that something has gone wrong and doesn't time out + // waiting for a response. + ZygoteConnection conn = peers.remove(pollIndex); + conn.closeSocket(); - // We don't know whether the remote side of the socket was closed or - // not until we attempt to read from it from processOneCommand. This - // shows up as a regular POLLIN event in our regular processing loop. - if (connection.isClosedByPeer()) { - connection.closeSocket(); - peers.remove(pollIndex); socketFDs.remove(pollIndex); + } else { + // We're in the child so any exception caught here has happened post + // fork and before we execute ActivityThread.main (or any other + // main() method). Log the details of the exception and bring down + // the process. + Log.e(TAG, "Caught post-fork exception in child process.", e); + throw e; } + } finally { + // Reset the child flag, in the event that the child process is a child- + // zygote. The flag will not be consulted this loop pass after the + // Runnable is returned. + mIsForkChild = false; } - } catch (Exception e) { - if (!mIsForkChild) { - // We're in the server so any exception here is one that has taken place - // pre-fork while processing commands or reading / writing from the - // control socket. Make a loud noise about any such exceptions so that - // we know exactly what failed and why. - - Slog.e(TAG, "Exception executing zygote command: ", e); - - // Make sure the socket is closed so that the other end knows - // immediately that something has gone wrong and doesn't time out - // waiting for a response. - ZygoteConnection conn = peers.remove(pollIndex); - conn.closeSocket(); - - socketFDs.remove(pollIndex); - } else { - // We're in the child so any exception caught here has happened post - // fork and before we execute ActivityThread.main (or any other main() - // method). Log the details of the exception and bring down the process. - Log.e(TAG, "Caught post-fork exception in child process.", e); - throw e; - } - } finally { - // Reset the child flag, in the event that the child process is a child- - // zygote. The flag will not be consulted this loop pass after the Runnable - // is returned. - mIsForkChild = false; - } - } else { - // Either the USAP pool event FD or a USAP reporting pipe. - - // If this is the event FD the payload will be the number of USAPs removed. - // If this is a reporting pipe FD the payload will be the PID of the USAP - // that was just specialized. - long messagePayload = -1; - - try { - byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; - int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); - if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { - DataInputStream inputStream = - new DataInputStream(new ByteArrayInputStream(buffer)); + } else { + // Either the USAP pool event FD or a USAP reporting pipe. + + // If this is the event FD the payload will be the number of USAPs removed. + // If this is a reporting pipe FD the payload will be the PID of the USAP + // that was just specialized. The `continue` statements below ensure that + // the messagePayload will always be valid if we complete the try block + // without an exception. + long messagePayload; + + try { + byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; + int readBytes = + Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); + + if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { + DataInputStream inputStream = + new DataInputStream(new ByteArrayInputStream(buffer)); + + messagePayload = inputStream.readLong(); + } else { + Log.e(TAG, "Incomplete read from USAP management FD of size " + + readBytes); + continue; + } + } catch (Exception ex) { + if (pollIndex == usapPoolEventFDIndex) { + Log.e(TAG, "Failed to read from USAP pool event FD: " + + ex.getMessage()); + } else { + Log.e(TAG, "Failed to read from USAP reporting pipe: " + + ex.getMessage()); + } - messagePayload = inputStream.readLong(); - } else { - Log.e(TAG, "Incomplete read from USAP management FD of size " - + readBytes); continue; } - } catch (Exception ex) { - if (pollIndex == usapPoolEventFDIndex) { - Log.e(TAG, "Failed to read from USAP pool event FD: " - + ex.getMessage()); - } else { - Log.e(TAG, "Failed to read from USAP reporting pipe: " - + ex.getMessage()); + + if (pollIndex > usapPoolEventFDIndex) { + Zygote.removeUsapTableEntry((int) messagePayload); } - continue; + usapPoolFDRead = true; } + } - if (pollIndex > usapPoolEventFDIndex) { - Zygote.removeUsapTableEntry((int) messagePayload); - } + if (usapPoolFDRead) { + int usapPoolCount = Zygote.getUsapPoolCount(); - usapPoolFDRead = true; + if (usapPoolCount < mUsapPoolSizeMin) { + // Immediate refill + mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE; + } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) { + // Delayed refill + mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis(); + } } } - // Check to see if the USAP pool needs to be refilled. - if (usapPoolFDRead) { + if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) { int[] sessionSocketRawFDs = socketFDs.subList(1, socketFDs.size()) .stream() .mapToInt(FileDescriptor::getInt$) .toArray(); - final Runnable command = fillUsapPool(sessionSocketRawFDs); + final boolean isPriorityRefill = + mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE; + + final Runnable command = + fillUsapPool(sessionSocketRawFDs, isPriorityRefill); if (command != null) { return command; + } else if (isPriorityRefill) { + // Schedule a delayed refill to finish refilling the pool. + mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis(); } } } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 07002d788908..81db4412cf8f 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -46,8 +46,8 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.WindowConfiguration; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java index 791c2d7aa4b2..f07f667f269f 100644 --- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java +++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java @@ -16,9 +16,9 @@ package com.android.internal.policy; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; import android.app.SearchManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -33,7 +33,6 @@ import android.view.FallbackEventHandler; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; -import com.android.internal.policy.PhoneWindow; /** * @hide diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index daa57e05aef6..a785ede3bcb2 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -34,10 +34,10 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.KeyguardManager; import android.app.SearchManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; diff --git a/core/java/com/android/internal/preference/YesNoPreference.java b/core/java/com/android/internal/preference/YesNoPreference.java index 94ef619f286a..f8780542f2fe 100644 --- a/core/java/com/android/internal/preference/YesNoPreference.java +++ b/core/java/com/android/internal/preference/YesNoPreference.java @@ -16,6 +16,7 @@ package com.android.internal.preference; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.os.Parcel; @@ -23,8 +24,6 @@ import android.os.Parcelable; import android.preference.DialogPreference; import android.util.AttributeSet; -import dalvik.annotation.compat.UnsupportedAppUsage; - /** * The {@link YesNoPreference} is a preference to show a dialog with Yes and No * buttons. diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index cb67309ce74f..6fd271c5490f 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -16,8 +16,8 @@ package com.android.internal.telephony; -import android.os.Bundle; import android.telephony.CallAttributes; +import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.PhoneCapability; @@ -37,8 +37,8 @@ oneway interface IPhoneStateListener { void onMessageWaitingIndicatorChanged(boolean mwi); void onCallForwardingIndicatorChanged(boolean cfi); - // we use bundle here instead of CellLocation so it can get the right subclass - void onCellLocationChanged(in Bundle location); + // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client. + void onCellLocationChanged(in CellIdentity location); void onCallStateChanged(int state, String incomingNumber); void onDataConnectionStateChanged(int state, int networkType); void onDataActivity(int direction); @@ -62,5 +62,6 @@ oneway interface IPhoneStateListener { void onOutgoingEmergencySms(in EmergencyNumber sentEmergencyNumber); void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause); void onImsCallDisconnectCauseChanged(in ImsReasonInfo imsReasonInfo); + void onRegistrationFailed(in CellIdentity cellIdentity, + String chosenPlmn, int domain, int causeCode, int additionalCauseCode); } - diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index b1bc2d9b510a..64b23610e4f9 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -19,8 +19,8 @@ package com.android.internal.telephony; import android.content.Intent; import android.net.LinkProperties; import android.net.NetworkCapabilities; -import android.os.Bundle; import android.telephony.CallQuality; +import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.ims.ImsReasonInfo; import android.telephony.PhoneCapability; @@ -33,16 +33,22 @@ import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; interface ITelephonyRegistry { - void addOnSubscriptionsChangedListener(String pkg, + void addOnSubscriptionsChangedListener(String pkg, String featureId, IOnSubscriptionsChangedListener callback); - void addOnOpportunisticSubscriptionsChangedListener(String pkg, + void addOnOpportunisticSubscriptionsChangedListener(String pkg, String featureId, IOnSubscriptionsChangedListener callback); void removeOnSubscriptionsChangedListener(String pkg, IOnSubscriptionsChangedListener callback); + /** + * @deprecated Use {@link #listenWithFeature(String, String, IPhoneStateListener, int, + * boolean) instead + */ @UnsupportedAppUsage void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow); - void listenForSubscriber(in int subId, String pkg, IPhoneStateListener callback, int events, + void listenWithFeature(String pkg, String featureId, IPhoneStateListener callback, int events, boolean notifyNow); + void listenForSubscriber(in int subId, String pkg, String featureId, + IPhoneStateListener callback, int events, boolean notifyNow); @UnsupportedAppUsage void notifyCallStateForAllSubs(int state, String incomingNumber); void notifyCallState(in int phoneId, in int subId, int state, String incomingNumber); @@ -61,9 +67,9 @@ interface ITelephonyRegistry { @UnsupportedAppUsage void notifyDataConnectionFailed(String apnType); void notifyDataConnectionFailedForSubscriber(int phoneId, int subId, String apnType); - @UnsupportedAppUsage(maxTargetSdk = 28) - void notifyCellLocation(in Bundle cellLocation); - void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation); + // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client. + void notifyCellLocation(in CellIdentity cellLocation); + void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation); @UnsupportedAppUsage void notifyCellInfo(in List<CellInfo> cellInfo); void notifyPreciseCallState(int phoneId, int subId, int ringingCallState, @@ -92,4 +98,6 @@ interface ITelephonyRegistry { void notifyCallQualityChanged(in CallQuality callQuality, int phoneId, int subId, int callNetworkType); void notifyImsDisconnectCause(int subId, in ImsReasonInfo imsReasonInfo); + void notifyRegistrationFailed(int slotIndex, int subId, in CellIdentity cellIdentity, + String chosenPlmn, int domain, int causeCode, int additionalCauseCode); } diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index b73ecd1974aa..5a9188018472 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -18,7 +18,7 @@ package com.android.internal.util; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.ArraySet; import dalvik.system.VMRuntime; diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java index b0888f2c8df9..f08771818873 100644 --- a/core/java/com/android/internal/util/AsyncChannel.java +++ b/core/java/com/android/internal/util/AsyncChannel.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/com/android/internal/util/BitwiseInputStream.java b/core/java/com/android/internal/util/BitwiseInputStream.java index 6ff67e9b9718..ffae3ce89ce4 100644 --- a/core/java/com/android/internal/util/BitwiseInputStream.java +++ b/core/java/com/android/internal/util/BitwiseInputStream.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An object that provides bitwise incremental read access to a byte array. diff --git a/core/java/com/android/internal/util/BitwiseOutputStream.java b/core/java/com/android/internal/util/BitwiseOutputStream.java index cdd6f173484c..9f4150860887 100644 --- a/core/java/com/android/internal/util/BitwiseOutputStream.java +++ b/core/java/com/android/internal/util/BitwiseOutputStream.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An object that provides bitwise incremental write access to a byte array. diff --git a/core/java/com/android/internal/util/CharSequences.java b/core/java/com/android/internal/util/CharSequences.java index 6b6c43ce8195..82ef200a73f1 100644 --- a/core/java/com/android/internal/util/CharSequences.java +++ b/core/java/com/android/internal/util/CharSequences.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * {@link CharSequence} utility methods. diff --git a/core/java/com/android/internal/util/ConnectivityUtil.java b/core/java/com/android/internal/util/ConnectivityUtil.java new file mode 100644 index 000000000000..b1d4fa0d3fd3 --- /dev/null +++ b/core/java/com/android/internal/util/ConnectivityUtil.java @@ -0,0 +1,202 @@ +/* + * 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.internal.util; + +import android.Manifest; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.os.Binder; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + + +/** + * Utility methods for common functionality using by different networks. + * + * @hide + */ +public class ConnectivityUtil { + + private static final String TAG = "ConnectivityUtil"; + + private final Context mContext; + private final AppOpsManager mAppOps; + private final UserManager mUserManager; + + public ConnectivityUtil(Context context) { + mContext = context; + mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + } + + /** + * API to determine if the caller has fine/coarse location permission (depending on + * config/targetSDK level) and the location mode is enabled for the user. SecurityException is + * thrown if the caller has no permission or the location mode is disabled. + * @param pkgName package name of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + */ + public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid, + @Nullable String message) + throws SecurityException { + checkPackage(uid, pkgName); + + // Location mode must be enabled + if (!isLocationModeEnabled()) { + // Location mode is disabled, scan results cannot be returned + throw new SecurityException("Location mode is disabled for the device"); + } + + // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to + // location information. + boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId, + uid, /* coarseForTargetSdkLessThanQ */ true, message); + + // If neither caller or app has location access, there is no need to check + // any other permissions. Deny access to scan results. + if (!canAppPackageUseLocation) { + throw new SecurityException("UID " + uid + " has no location permission"); + } + // If the User or profile is current, permission is granted + // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. + if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) { + throw new SecurityException("UID " + uid + " profile not permitted"); + } + } + + /** + * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or + * android.Manifest.permission.ACCESS_COARSE_LOCATION (depending on config/targetSDK level) + * and a corresponding app op is allowed for this package and uid. + * + * @param pkgName PackageName of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE + * else (false or targetSDK >= Q) then will check for FINE + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + */ + public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId, + int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) { + boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid); + + String permissionType = Manifest.permission.ACCESS_FINE_LOCATION; + if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { + // Having FINE permission implies having COARSE permission (but not the reverse) + permissionType = Manifest.permission.ACCESS_COARSE_LOCATION; + } + if (getUidPermission(permissionType, uid) + == PackageManager.PERMISSION_DENIED) { + return false; + } + + // Always checking FINE - even if will not enforce. This will record the request for FINE + // so that a location request by the app is surfaced to the user. + boolean isFineLocationAllowed = noteAppOpAllowed( + AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message); + if (isFineLocationAllowed) { + return true; + } + if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { + return noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, featureId, uid, + message); + } + return false; + } + + /** + * Retrieves a handle to LocationManager (if not already done) and check if location is enabled. + */ + public boolean isLocationModeEnabled() { + LocationManager locationManager = + (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); + try { + return locationManager.isLocationEnabledForUser(UserHandle.of( + getCurrentUser())); + } catch (Exception e) { + Log.e(TAG, "Failure to get location mode via API, falling back to settings", e); + return false; + } + } + + private boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) { + long ident = Binder.clearCallingIdentity(); + try { + if (mContext.getPackageManager().getApplicationInfoAsUser( + packageName, 0, + UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion + < versionCode) { + return true; + } + } catch (PackageManager.NameNotFoundException e) { + // In case of exception, assume unknown app (more strict checking) + // Note: This case will never happen since checkPackage is + // called to verify validity before checking App's version. + } finally { + Binder.restoreCallingIdentity(ident); + } + return false; + } + + private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, + int uid, @Nullable String message) { + return mAppOps.noteOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED; + } + + private void checkPackage(int uid, String pkgName) throws SecurityException { + if (pkgName == null) { + throw new SecurityException("Checking UID " + uid + " but Package Name is Null"); + } + mAppOps.checkPackage(uid, pkgName); + } + + private boolean isCurrentProfile(int uid) { + UserHandle currentUser = UserHandle.of(getCurrentUser()); + UserHandle callingUser = UserHandle.getUserHandleForUid(uid); + return currentUser.equals(callingUser) + || mUserManager.isSameProfileGroup( + currentUser.getIdentifier(), callingUser.getIdentifier()); + } + + private boolean checkInteractAcrossUsersFull(int uid) { + return getUidPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) + == PackageManager.PERMISSION_GRANTED; + } + + @VisibleForTesting + protected int getCurrentUser() { + return ActivityManager.getCurrentUser(); + } + + private int getUidPermission(String permissionType, int uid) { + // We don't care about pid, pass in -1 + return mContext.checkPermission(permissionType, -1, uid); + } +} diff --git a/core/java/com/android/internal/util/FastMath.java b/core/java/com/android/internal/util/FastMath.java index 35efe708795e..b7dbee53a4be 100644 --- a/core/java/com/android/internal/util/FastMath.java +++ b/core/java/com/android/internal/util/FastMath.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Fast and loose math routines. diff --git a/core/java/com/android/internal/util/FastPrintWriter.java b/core/java/com/android/internal/util/FastPrintWriter.java index 981fbaaa9880..63124def6d2f 100644 --- a/core/java/com/android/internal/util/FastPrintWriter.java +++ b/core/java/com/android/internal/util/FastPrintWriter.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; import android.util.Printer; diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java index 9f76aeb663c5..94e07a85867e 100644 --- a/core/java/com/android/internal/util/FastXmlSerializer.java +++ b/core/java/com/android/internal/util/FastXmlSerializer.java @@ -16,9 +16,10 @@ package com.android.internal.util; +import android.compat.annotation.UnsupportedAppUsage; + import org.xmlpull.v1.XmlSerializer; -import android.annotation.UnsupportedAppUsage; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; diff --git a/core/java/com/android/internal/util/GrowingArrayUtils.java b/core/java/com/android/internal/util/GrowingArrayUtils.java index 9f563667e019..597fe6b53d11 100644 --- a/core/java/com/android/internal/util/GrowingArrayUtils.java +++ b/core/java/com/android/internal/util/GrowingArrayUtils.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A helper class that aims to provide comparable growth performance to ArrayList, but on primitive diff --git a/core/java/com/android/internal/util/HexDump.java b/core/java/com/android/internal/util/HexDump.java index 6ffc92853b08..ad88dd6deec6 100644 --- a/core/java/com/android/internal/util/HexDump.java +++ b/core/java/com/android/internal/util/HexDump.java @@ -17,7 +17,7 @@ package com.android.internal.util; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class HexDump { diff --git a/core/java/com/android/internal/util/IState.java b/core/java/com/android/internal/util/IState.java index eb66e2ce94d7..07837bf8f587 100644 --- a/core/java/com/android/internal/util/IState.java +++ b/core/java/com/android/internal/util/IState.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Message; /** diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java index 03a555edf4a8..34c6a055d5bd 100644 --- a/core/java/com/android/internal/util/IndentingPrintWriter.java +++ b/core/java/com/android/internal/util/IndentingPrintWriter.java @@ -16,7 +16,8 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.PrintWriter; import java.io.Writer; import java.util.Arrays; diff --git a/core/java/com/android/internal/util/JournaledFile.java b/core/java/com/android/internal/util/JournaledFile.java index 065cc5b2416b..a9d8f7239d03 100644 --- a/core/java/com/android/internal/util/JournaledFile.java +++ b/core/java/com/android/internal/util/JournaledFile.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import java.io.File; diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java index 580c2fa66de2..5de77d9b0545 100644 --- a/core/java/com/android/internal/util/MemInfoReader.java +++ b/core/java/com/android/internal/util/MemInfoReader.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Debug; import android.os.StrictMode; diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java index 3fff5c233890..408a7a8e139a 100644 --- a/core/java/com/android/internal/util/Preconditions.java +++ b/core/java/com/android/internal/util/Preconditions.java @@ -18,7 +18,7 @@ package com.android.internal.util; import android.annotation.IntRange; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.text.TextUtils; import java.util.Collection; @@ -126,7 +126,9 @@ public class Preconditions { * @param reference an object reference * @return the non-null reference that was validated * @throws NullPointerException if {@code reference} is null + * @deprecated - use {@link java.util.Objects.requireNonNull} instead. */ + @Deprecated @UnsupportedAppUsage public static @NonNull <T> T checkNotNull(final T reference) { if (reference == null) { @@ -144,7 +146,9 @@ public class Preconditions { * be converted to a string using {@link String#valueOf(Object)} * @return the non-null reference that was validated * @throws NullPointerException if {@code reference} is null + * @deprecated - use {@link java.util.Objects.requireNonNull} instead. */ + @Deprecated @UnsupportedAppUsage public static @NonNull <T> T checkNotNull(final T reference, final Object errorMessage) { if (reference == null) { @@ -154,26 +158,6 @@ public class Preconditions { } /** - * Ensures that an object reference passed as a parameter to the calling - * method is not null. - * - * @param reference an object reference - * @param messageTemplate a printf-style message template to use if the check fails; will - * be converted to a string using {@link String#format(String, Object...)} - * @param messageArgs arguments for {@code messageTemplate} - * @return the non-null reference that was validated - * @throws NullPointerException if {@code reference} is null - */ - public static @NonNull <T> T checkNotNull(final T reference, - final String messageTemplate, - final Object... messageArgs) { - if (reference == null) { - throw new NullPointerException(String.format(messageTemplate, messageArgs)); - } - return reference; - } - - /** * Ensures the truth of an expression involving the state of the calling * instance, but not involving any parameters to the calling method. * diff --git a/core/java/com/android/internal/util/State.java b/core/java/com/android/internal/util/State.java index 3c61e035e886..636378e32091 100644 --- a/core/java/com/android/internal/util/State.java +++ b/core/java/com/android/internal/util/State.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Message; /** diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java index 6c217e5a37bf..0c2406559dcc 100644 --- a/core/java/com/android/internal/util/StateMachine.java +++ b/core/java/com/android/internal/util/StateMachine.java @@ -16,7 +16,7 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index 8799e3d4c6bf..c1be33a215b8 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -16,10 +16,10 @@ package com.android.internal.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; import android.net.Uri; import android.text.TextUtils; import android.util.ArrayMap; diff --git a/core/java/com/android/internal/view/ActionBarPolicy.java b/core/java/com/android/internal/view/ActionBarPolicy.java index d18c35e703da..d16cb4362f1b 100644 --- a/core/java/com/android/internal/view/ActionBarPolicy.java +++ b/core/java/com/android/internal/view/ActionBarPolicy.java @@ -16,15 +16,15 @@ package com.android.internal.view; -import com.android.internal.R; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Build; +import com.android.internal.R; + /** * Allows components to query for various configuration policy decisions * about how the action bar should lay out and behave on the current device. diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index f5a9fde97159..adf56bf8a434 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -16,7 +16,7 @@ package com.android.internal.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Point; import android.graphics.Rect; import android.hardware.input.InputManager; diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java index ececba13c760..6278d4a35329 100644 --- a/core/java/com/android/internal/view/IInputConnectionWrapper.java +++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java @@ -18,7 +18,7 @@ package com.android.internal.view; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.Handler; diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java index 1b133d2a8393..a5964b509b3c 100644 --- a/core/java/com/android/internal/view/InputBindResult.java +++ b/core/java/com/android/internal/view/InputBindResult.java @@ -20,7 +20,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java index 0c057ea6df59..a41048c0f426 100644 --- a/core/java/com/android/internal/view/InputConnectionWrapper.java +++ b/core/java/com/android/internal/view/InputConnectionWrapper.java @@ -19,7 +19,7 @@ package com.android.internal.view; import android.annotation.AnyThread; import android.annotation.BinderThread; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.inputmethodservice.AbstractInputMethodService; import android.os.Bundle; import android.os.Handler; diff --git a/core/java/com/android/internal/view/WindowManagerPolicyThread.java b/core/java/com/android/internal/view/WindowManagerPolicyThread.java index b009a2d8ca30..6d691fce4fb0 100644 --- a/core/java/com/android/internal/view/WindowManagerPolicyThread.java +++ b/core/java/com/android/internal/view/WindowManagerPolicyThread.java @@ -16,7 +16,7 @@ package com.android.internal.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; /** diff --git a/core/java/com/android/internal/view/menu/ActionMenu.java b/core/java/com/android/internal/view/menu/ActionMenu.java index 977c1f6fda7b..648262965ab1 100644 --- a/core/java/com/android/internal/view/menu/ActionMenu.java +++ b/core/java/com/android/internal/view/menu/ActionMenu.java @@ -16,10 +16,7 @@ package com.android.internal.view.menu; -import java.util.ArrayList; -import java.util.List; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -30,6 +27,9 @@ import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; +import java.util.ArrayList; +import java.util.List; + /** * @hide */ diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java index ed253d58fb82..bd8bcb9cf81e 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuItem.java +++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java @@ -17,7 +17,7 @@ package com.android.internal.view.menu; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java index eb94db33ba1a..7622b939b6eb 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java @@ -16,7 +16,7 @@ package com.android.internal.view.menu; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java index 3d3aceb4a85f..a9f5e47fc83f 100644 --- a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java +++ b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java @@ -16,7 +16,7 @@ package com.android.internal.view.menu; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.IBinder; diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java index 3d888d347d65..539c71e5c473 100644 --- a/core/java/com/android/internal/view/menu/IconMenuItemView.java +++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java @@ -16,13 +16,12 @@ package com.android.internal.view.menu; -import com.android.internal.view.menu.MenuBuilder.ItemInvoker; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.text.Layout; import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; @@ -30,7 +29,8 @@ import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewDebug; import android.widget.TextView; -import android.text.Layout; + +import com.android.internal.view.menu.MenuBuilder.ItemInvoker; /** * The item view for each item in the {@link IconMenuView}. diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java index 6f264341f7b4..9e240dbd8a21 100644 --- a/core/java/com/android/internal/view/menu/IconMenuView.java +++ b/core/java/com/android/internal/view/menu/IconMenuView.java @@ -16,9 +16,7 @@ package com.android.internal.view.menu; -import com.android.internal.view.menu.MenuBuilder.ItemInvoker; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; @@ -29,10 +27,12 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.LayoutInflater; + +import com.android.internal.view.menu.MenuBuilder.ItemInvoker; import java.util.ArrayList; diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index 0e07ca79faf7..b31ae38b4566 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -18,7 +18,7 @@ package com.android.internal.view.menu; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java index 88d0a03bd55f..d02b8f6ceb63 100644 --- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java +++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java @@ -16,9 +16,9 @@ package com.android.internal.view.menu; -import android.annotation.UnsupportedAppUsage; import android.app.AlertDialog; import android.app.Dialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.DialogInterface; import android.os.IBinder; import android.view.KeyEvent; diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 994a9c117ce9..218f5185ec47 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -16,10 +16,8 @@ package com.android.internal.view.menu; -import com.android.internal.view.menu.MenuView.ItemView; - import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -39,6 +37,8 @@ import android.view.ViewConfiguration; import android.view.ViewDebug; import android.widget.LinearLayout; +import com.android.internal.view.menu.MenuView.ItemView; + /** * @hide */ diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index d00108edefd0..bac602509148 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -20,7 +20,7 @@ import android.annotation.AttrRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; diff --git a/core/java/com/android/internal/view/menu/MenuPresenter.java b/core/java/com/android/internal/view/menu/MenuPresenter.java index c5df8ad6edc6..35b8fefe75ab 100644 --- a/core/java/com/android/internal/view/menu/MenuPresenter.java +++ b/core/java/com/android/internal/view/menu/MenuPresenter.java @@ -18,7 +18,7 @@ package com.android.internal.view.menu; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Parcelable; import android.view.ViewGroup; diff --git a/core/java/com/android/internal/view/menu/MenuView.java b/core/java/com/android/internal/view/menu/MenuView.java index 67a55308938d..a31c820cd2a6 100644 --- a/core/java/com/android/internal/view/menu/MenuView.java +++ b/core/java/com/android/internal/view/menu/MenuView.java @@ -16,10 +16,7 @@ package com.android.internal.view.menu; -import com.android.internal.view.menu.MenuBuilder; -import com.android.internal.view.menu.MenuItemImpl; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.drawable.Drawable; /** diff --git a/core/java/com/android/internal/view/menu/SubMenuBuilder.java b/core/java/com/android/internal/view/menu/SubMenuBuilder.java index cf6d9746bb93..6eb215e94093 100644 --- a/core/java/com/android/internal/view/menu/SubMenuBuilder.java +++ b/core/java/com/android/internal/view/menu/SubMenuBuilder.java @@ -16,7 +16,7 @@ package com.android.internal.view.menu; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.drawable.Drawable; import android.view.Menu; diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java index 9ccee7fc32ff..0f0c1a3de3a2 100644 --- a/core/java/com/android/internal/widget/AbsActionBarView.java +++ b/core/java/com/android/internal/widget/AbsActionBarView.java @@ -15,26 +15,25 @@ */ package com.android.internal.widget; -import com.android.internal.R; - -import android.util.TypedValue; -import android.view.ContextThemeWrapper; -import android.view.MotionEvent; -import android.widget.ActionMenuPresenter; -import android.widget.ActionMenuView; - import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.ContextThemeWrapper; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; +import android.widget.ActionMenuPresenter; +import android.widget.ActionMenuView; + +import com.android.internal.R; public abstract class AbsActionBarView extends ViewGroup { private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator(); diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java index 78ed53fa918c..051526ef2da7 100644 --- a/core/java/com/android/internal/widget/ActionBarContextView.java +++ b/core/java/com/android/internal/widget/ActionBarContextView.java @@ -15,13 +15,7 @@ */ package com.android.internal.widget; -import com.android.internal.R; - -import android.widget.ActionMenuPresenter; -import android.widget.ActionMenuView; -import com.android.internal.view.menu.MenuBuilder; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; @@ -32,9 +26,14 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; +import android.widget.ActionMenuPresenter; +import android.widget.ActionMenuView; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.internal.R; +import com.android.internal.view.menu.MenuBuilder; + /** * @hide */ diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java index e9e3cdab7a10..aca0b713686f 100644 --- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java +++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java @@ -18,7 +18,7 @@ package com.android.internal.widget; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -41,6 +41,7 @@ import android.view.Window; import android.view.WindowInsets; import android.widget.OverScroller; import android.widget.Toolbar; + import com.android.internal.view.menu.MenuPresenter; /** diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java index 7a0174946671..d879b6d569f3 100644 --- a/core/java/com/android/internal/widget/AlertDialogLayout.java +++ b/core/java/com/android/internal/widget/AlertDialogLayout.java @@ -18,8 +18,8 @@ package com.android.internal.widget; import android.annotation.AttrRes; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.annotation.StyleRes; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java index 0ca67438c5c3..ff131071efef 100644 --- a/core/java/com/android/internal/widget/ButtonBarLayout.java +++ b/core/java/com/android/internal/widget/ButtonBarLayout.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java index 35bff6d7c430..74ad81566ef4 100644 --- a/core/java/com/android/internal/widget/CachingIconView.java +++ b/core/java/com/android/internal/widget/CachingIconView.java @@ -18,7 +18,7 @@ package com.android.internal.widget; import android.annotation.DrawableRes; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.graphics.Bitmap; diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java index 405436c53ff0..0bfd684317fd 100644 --- a/core/java/com/android/internal/widget/DialogTitle.java +++ b/core/java/com/android/internal/widget/DialogTitle.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.text.Layout; diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java index 2b648e90f7dd..ff3543c837eb 100644 --- a/core/java/com/android/internal/widget/EditableInputConnection.java +++ b/core/java/com/android/internal/widget/EditableInputConnection.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.text.Editable; import android.text.method.KeyListener; diff --git a/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java b/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java index cc7911da0b96..9ef9f697c46c 100644 --- a/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java +++ b/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java @@ -16,12 +16,12 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; -import android.view.View; import android.view.MotionEvent; +import android.view.View; import android.widget.LinearLayout; diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java index 09bc28c1f5ec..d78b26ab6dcb 100644 --- a/core/java/com/android/internal/widget/LockPatternChecker.java +++ b/core/java/com/android/internal/widget/LockPatternChecker.java @@ -1,6 +1,6 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.AsyncTask; import com.android.internal.widget.LockPatternUtils.RequestThrottledException; diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index dc45f7834748..8ecee6271f83 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -27,11 +27,11 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import android.annotation.IntDef; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.admin.DevicePolicyManager; import android.app.admin.PasswordMetrics; import android.app.trust.IStrongAuthTracker; import android.app.trust.TrustManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -58,10 +58,10 @@ import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; -import com.google.android.collect.Lists; - import libcore.util.HexEncoding; +import com.google.android.collect.Lists; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.security.MessageDigest; diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 3f6c4d4f5634..591a5e82d5e4 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -19,7 +19,7 @@ package com.android.internal.widget; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; diff --git a/core/java/com/android/internal/widget/NumericTextView.java b/core/java/com/android/internal/widget/NumericTextView.java index d2156704a655..c8f901133be6 100644 --- a/core/java/com/android/internal/widget/NumericTextView.java +++ b/core/java/com/android/internal/widget/NumericTextView.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index 1f5b0701d2a7..37365111b0c5 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; diff --git a/core/java/com/android/internal/widget/PreferenceImageView.java b/core/java/com/android/internal/widget/PreferenceImageView.java index 02a0b8d436b9..43b6b5a169c5 100644 --- a/core/java/com/android/internal/widget/PreferenceImageView.java +++ b/core/java/com/android/internal/widget/PreferenceImageView.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.AttributeSet; import android.widget.ImageView; diff --git a/core/java/com/android/internal/widget/RecyclerView.java b/core/java/com/android/internal/widget/RecyclerView.java index b66a7b44f05d..43a227a32346 100644 --- a/core/java/com/android/internal/widget/RecyclerView.java +++ b/core/java/com/android/internal/widget/RecyclerView.java @@ -20,7 +20,7 @@ import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.database.Observable; diff --git a/core/java/com/android/internal/widget/ScrollBarUtils.java b/core/java/com/android/internal/widget/ScrollBarUtils.java index 982e3152fc7c..3e9d697a0ace 100644 --- a/core/java/com/android/internal/widget/ScrollBarUtils.java +++ b/core/java/com/android/internal/widget/ScrollBarUtils.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class ScrollBarUtils { diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java index 5d48ab910439..aa0b0bbd4c19 100644 --- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java +++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java @@ -15,13 +15,11 @@ */ package com.android.internal.widget; -import com.android.internal.view.ActionBarPolicy; - import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; -import android.annotation.UnsupportedAppUsage; import android.app.ActionBar; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; @@ -42,6 +40,8 @@ import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; +import com.android.internal.view.ActionBarPolicy; + /** * This widget implements the dynamic action bar tab behavior that can change * across different configurations or circumstances. diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java index 4b5d62467af0..5e6f3a46de7d 100644 --- a/core/java/com/android/internal/widget/SlidingTab.java +++ b/core/java/com/android/internal/widget/SlidingTab.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; @@ -34,12 +34,12 @@ import android.view.View; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; +import android.view.animation.Animation.AnimationListener; import android.view.animation.LinearInterpolator; import android.view.animation.TranslateAnimation; -import android.view.animation.Animation.AnimationListener; import android.widget.ImageView; -import android.widget.TextView; import android.widget.ImageView.ScaleType; +import android.widget.TextView; import com.android.internal.R; diff --git a/core/java/com/android/internal/widget/TextViewInputDisabler.java b/core/java/com/android/internal/widget/TextViewInputDisabler.java index 8d8f0fe52d64..57806eb21dcf 100644 --- a/core/java/com/android/internal/widget/TextViewInputDisabler.java +++ b/core/java/com/android/internal/widget/TextViewInputDisabler.java @@ -16,7 +16,7 @@ package com.android.internal.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.text.InputFilter; import android.text.Spanned; import android.widget.TextView; diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java index 7d36b02d4157..c8a86d108134 100644 --- a/core/java/com/android/internal/widget/ViewPager.java +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -18,7 +18,7 @@ package com.android.internal.widget; import android.annotation.DrawableRes; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; diff --git a/core/java/com/android/server/ResettableTimeout.java b/core/java/com/android/server/ResettableTimeout.java index 64083f72aff5..511af941bf76 100644 --- a/core/java/com/android/server/ResettableTimeout.java +++ b/core/java/com/android/server/ResettableTimeout.java @@ -16,10 +16,9 @@ package com.android.server; -import android.os.SystemClock; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ConditionVariable; +import android.os.SystemClock; /** * Utility class that you can call on with a timeout, and get called back diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java index e1a10a5805f5..2a9c0b44b45e 100644 --- a/core/java/com/android/server/net/BaseNetworkObserver.java +++ b/core/java/com/android/server/net/BaseNetworkObserver.java @@ -16,7 +16,7 @@ package com.android.server.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.INetworkManagementEventObserver; import android.net.LinkAddress; import android.net.RouteInfo; diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java index 647fb5b9d079..b57397f46a7e 100644 --- a/core/java/com/android/server/net/NetlinkTracker.java +++ b/core/java/com/android/server/net/NetlinkTracker.java @@ -16,7 +16,7 @@ package com.android.server.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.RouteInfo; diff --git a/core/java/com/google/android/collect/Lists.java b/core/java/com/google/android/collect/Lists.java index 8f6594aefb0a..585847da566c 100644 --- a/core/java/com/google/android/collect/Lists.java +++ b/core/java/com/google/android/collect/Lists.java @@ -16,7 +16,8 @@ package com.google.android.collect; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; import java.util.Collections; diff --git a/core/java/com/google/android/collect/Maps.java b/core/java/com/google/android/collect/Maps.java index 6ba33207631a..cd4c1280545e 100644 --- a/core/java/com/google/android/collect/Maps.java +++ b/core/java/com/google/android/collect/Maps.java @@ -16,7 +16,7 @@ package com.google.android.collect; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; import java.util.HashMap; diff --git a/core/java/com/google/android/collect/Sets.java b/core/java/com/google/android/collect/Sets.java index 09b5e51ae2c6..c67a88a19080 100644 --- a/core/java/com/google/android/collect/Sets.java +++ b/core/java/com/google/android/collect/Sets.java @@ -16,7 +16,7 @@ package com.google.android.collect; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.ArraySet; import java.util.Collections; diff --git a/core/java/com/google/android/util/AbstractMessageParser.java b/core/java/com/google/android/util/AbstractMessageParser.java index 00fcb16f6d3a..b41ac1f36a91 100644 --- a/core/java/com/google/android/util/AbstractMessageParser.java +++ b/core/java/com/google/android/util/AbstractMessageParser.java @@ -16,7 +16,7 @@ package com.google.android.util; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.ArrayList; import java.util.HashMap; diff --git a/core/java/org/apache/http/conn/ssl/AbstractVerifier.java b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java index 36d6e22ca847..2848ad7796af 100644 --- a/core/java/org/apache/http/conn/ssl/AbstractVerifier.java +++ b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java @@ -31,7 +31,7 @@ package org.apache.http.conn.ssl; -import java.util.regex.Pattern; +import android.compat.annotation.UnsupportedAppUsage; import java.io.IOException; import java.security.cert.Certificate; @@ -43,10 +43,10 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; -import java.util.logging.Logger; import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; -import android.annotation.UnsupportedAppUsage; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; diff --git a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java index b2e8b5e7af05..ffae7570ea79 100644 --- a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java +++ b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java @@ -31,20 +31,14 @@ package org.apache.http.conn.ssl; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; + import org.apache.http.conn.scheme.HostNameResolver; import org.apache.http.conn.scheme.LayeredSocketFactory; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; -import android.annotation.UnsupportedAppUsage; -import android.os.Build; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -57,6 +51,14 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + /** * Layered socket factory for TLS/SSL connections, based on JSSE. *. diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 08aa1d97fa1c..ba7fe7ff8739 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -24,9 +24,7 @@ #include <linux/tcp.h> #include <net/if.h> #include <netinet/ether.h> -#include <netinet/icmp6.h> #include <netinet/ip.h> -#include <netinet/ip6.h> #include <netinet/udp.h> #include <android_runtime/AndroidRuntime.h> @@ -102,98 +100,6 @@ static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobjec } } -static void android_net_utils_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd, - jint ifIndex) -{ - static const int kLinkLocalHopLimit = 255; - - int fd = jniGetFDFromFileDescriptor(env, javaFd); - - // Set an ICMPv6 filter that only passes Router Solicitations. - struct icmp6_filter rs_only; - ICMP6_FILTER_SETBLOCKALL(&rs_only); - ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &rs_only); - socklen_t len = sizeof(rs_only); - if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &rs_only, len) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(ICMP6_FILTER): %s", strerror(errno)); - return; - } - - // Most/all of the rest of these options can be set via Java code, but - // because we're here on account of setting an icmp6_filter go ahead - // and do it all natively for now. - // - // TODO: Consider moving these out to Java. - - // Set the multicast hoplimit to 255 (link-local only). - int hops = kLinkLocalHopLimit; - len = sizeof(hops); - if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, len) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno)); - return; - } - - // Set the unicast hoplimit to 255 (link-local only). - hops = kLinkLocalHopLimit; - len = sizeof(hops); - if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, len) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno)); - return; - } - - // Explicitly disable multicast loopback. - int off = 0; - len = sizeof(off); - if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, len) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(IPV6_MULTICAST_LOOP): %s", strerror(errno)); - return; - } - - // Specify the IPv6 interface to use for outbound multicast. - len = sizeof(ifIndex); - if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, len) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errno)); - return; - } - - // Additional options to be considered: - // - IPV6_TCLASS - // - IPV6_RECVPKTINFO - // - IPV6_RECVHOPLIMIT - - // Bind to [::]. - const struct sockaddr_in6 sin6 = { - .sin6_family = AF_INET6, - .sin6_port = 0, - .sin6_flowinfo = 0, - .sin6_addr = IN6ADDR_ANY_INIT, - .sin6_scope_id = 0, - }; - auto sa = reinterpret_cast<const struct sockaddr *>(&sin6); - len = sizeof(sin6); - if (bind(fd, sa, len) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "bind(IN6ADDR_ANY): %s", strerror(errno)); - return; - } - - // Join the all-routers multicast group, ff02::2%index. - struct ipv6_mreq all_rtrs = { - .ipv6mr_multiaddr = {{{0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}}, - .ipv6mr_interface = ifIndex, - }; - len = sizeof(all_rtrs); - if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &all_rtrs, len) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno)); - return; - } -} static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId) { @@ -370,7 +276,6 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter }, { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter }, { "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow }, - { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket }, { "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend }, { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery }, { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult }, diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 52ce54bc8924..7bf35f9a9864 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -193,7 +193,8 @@ static int read_memtrack_memory(struct memtrack_proc* p, int pid, { int err = memtrack_proc_get(p, pid); if (err != 0) { - ALOGW("failed to get memory consumption info: %d", err); + // The memtrack HAL may not be available, do not log to avoid flooding + // logcat. return err; } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 58fd9c0ab85e..486df621f4f1 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -63,6 +63,7 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> +#include <sys/un.h> #include <sys/utsname.h> #include <sys/wait.h> #include <unistd.h> @@ -164,11 +165,26 @@ static std::atomic_uint32_t gUsapPoolCount = 0; static int gUsapPoolEventFD = -1; /** + * The socket file descriptor used to send notifications to the + * system_server. + */ +static int gSystemServerSocketFd = -1; + +/** * The maximum value that the gUSAPPoolSizeMax variable may take. This value * is a mirror of ZygoteServer.USAP_POOL_SIZE_MAX_LIMIT */ static constexpr int USAP_POOL_SIZE_MAX_LIMIT = 100; +/** The numeric value for the maximum priority a process may possess. */ +static constexpr int PROCESS_PRIORITY_MAX = -20; + +/** The numeric value for the minimum priority a process may possess. */ +static constexpr int PROCESS_PRIORITY_MIN = 19; + +/** The numeric value for the normal priority a process should have. */ +static constexpr int PROCESS_PRIORITY_DEFAULT = 0; + /** * A helper class containing accounting information for USAPs. */ @@ -305,6 +321,26 @@ enum RuntimeFlags : uint32_t { PROFILE_FROM_SHELL = 1 << 15, }; +enum UnsolicitedZygoteMessageTypes : uint32_t { + UNSOLICITED_ZYGOTE_MESSAGE_TYPE_RESERVED = 0, + UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD = 1, +}; + +struct UnsolicitedZygoteMessageSigChld { + struct { + UnsolicitedZygoteMessageTypes type; + } header; + struct { + pid_t pid; + uid_t uid; + int status; + } payload; +}; + +// Keep sync with services/core/java/com/android/server/am/ProcessList.java +static constexpr struct sockaddr_un kSystemServerSockAddr = + {.sun_family = AF_LOCAL, .sun_path = "/data/system/unsolzygotesocket"}; + // Forward declaration so we don't have to move the signal handler. static bool RemoveUsapTableEntry(pid_t usap_pid); @@ -314,8 +350,37 @@ static void RuntimeAbort(JNIEnv* env, int line, const char* msg) { env->FatalError(oss.str().c_str()); } +// Create the socket which is going to be used to send unsolicited message +// to system_server, the socket will be closed post forking a child process. +// It's expected to be called at each zygote's initialization. +static void initUnsolSocketToSystemServer() { + gSystemServerSocketFd = socket(AF_LOCAL, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (gSystemServerSocketFd >= 0) { + ALOGV("Zygote:systemServerSocketFD = %d", gSystemServerSocketFd); + } else { + ALOGE("Unable to create socket file descriptor to connect to system_server"); + } +} + +static void sendSigChildStatus(const pid_t pid, const uid_t uid, const int status) { + int socketFd = gSystemServerSocketFd; + if (socketFd >= 0) { + // fill the message buffer + struct UnsolicitedZygoteMessageSigChld data = + {.header = {.type = UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD}, + .payload = {.pid = pid, .uid = uid, .status = status}}; + if (TEMP_FAILURE_RETRY( + sendto(socketFd, &data, sizeof(data), 0, + reinterpret_cast<const struct sockaddr*>(&kSystemServerSockAddr), + sizeof(kSystemServerSockAddr))) == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, + "Zygote failed to write to system_server FD: %s", + strerror(errno)); + } + } +} // This signal handler is for zygote mode, since the zygote must reap its children -static void SigChldHandler(int /*signal_number*/) { +static void SigChldHandler(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) { pid_t pid; int status; int64_t usaps_removed = 0; @@ -329,6 +394,8 @@ static void SigChldHandler(int /*signal_number*/) { int saved_errno = errno; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + // Notify system_server that we received a SIGCHLD + sendSigChildStatus(pid, info->si_uid, status); // Log process-death status that we care about. if (WIFEXITED(status)) { async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, @@ -402,8 +469,7 @@ static void SigChldHandler(int /*signal_number*/) { // This ends up being called repeatedly before each fork(), but there's // no real harm in that. static void SetSignalHandlers() { - struct sigaction sig_chld = {}; - sig_chld.sa_handler = SigChldHandler; + struct sigaction sig_chld = {.sa_flags = SA_SIGINFO, .sa_sigaction = SigChldHandler}; if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) { ALOGW("Error setting SIGCHLD handler: %s", strerror(errno)); @@ -903,7 +969,8 @@ static void ClearUsapTable() { // Utility routine to fork a process from the zygote. static pid_t ForkCommon(JNIEnv* env, bool is_system_server, const std::vector<int>& fds_to_close, - const std::vector<int>& fds_to_ignore) { + const std::vector<int>& fds_to_ignore, + bool is_priority_fork) { SetSignalHandlers(); // Curry a failure function. @@ -936,6 +1003,12 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server, pid_t pid = fork(); if (pid == 0) { + if (is_priority_fork) { + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); + } else { + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); + } + // The child process. PreApplicationInit(); @@ -951,6 +1024,9 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server, // Turn fdsan back on. android_fdsan_set_error_level(fdsan_error_level); + + // Reset the fd to the unsolicited zygote socket + gSystemServerSocketFd = -1; } else { ALOGD("Forked child process %d", pid); } @@ -987,22 +1063,16 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, DropCapabilitiesBoundingSet(fail_fn); - bool use_native_bridge = !is_system_server && - instruction_set.has_value() && - android::NativeBridgeAvailable() && - android::NeedsNativeBridge(instruction_set.value().c_str()); - - if (use_native_bridge && !app_data_dir.has_value()) { - // The app_data_dir variable should never be empty if we need to use a - // native bridge. In general, app_data_dir will never be empty for normal - // applications. It can only happen in special cases (for isolated - // processes which are not associated with any app). These are launched by - // the framework and should not be emulated anyway. - use_native_bridge = false; - ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr."); - } + bool need_pre_initialize_native_bridge = + !is_system_server && + instruction_set.has_value() && + android::NativeBridgeAvailable() && + // Native bridge may be already initialized if this + // is an app forked from app-zygote. + !android::NativeBridgeInitialized() && + android::NeedsNativeBridge(instruction_set.value().c_str()); - MountEmulatedStorage(uid, mount_external, use_native_bridge, fail_fn); + MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn); // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. @@ -1018,11 +1088,12 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, SetGids(env, gids, fail_fn); SetRLimits(env, rlimits, fail_fn); - if (use_native_bridge) { - // Due to the logic behind use_native_bridge we know that both app_data_dir - // and instruction_set contain values. - android::PreInitializeNativeBridge(app_data_dir.value().c_str(), - instruction_set.value().c_str()); + if (need_pre_initialize_native_bridge) { + // Due to the logic behind need_pre_initialize_native_bridge we know that + // instruction_set contains a value. + android::PreInitializeNativeBridge( + app_data_dir.has_value() ? app_data_dir.value().c_str() : nullptr, + instruction_set.value().c_str()); } if (setresgid(gid, gid, gid) == -1) { @@ -1130,9 +1201,16 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, } } + if (is_child_zygote) { + initUnsolSocketToSystemServer(); + } + env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, is_system_server, is_child_zygote, managed_instruction_set); + // Reset the process priority to the default value. + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT); + if (env->ExceptionCheck()) { fail_fn("Error calling post fork hooks."); } @@ -1372,7 +1450,12 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( fds_to_ignore.push_back(gUsapPoolEventFD); } - pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore); + if (gSystemServerSocketFd != -1) { + fds_to_close.push_back(gSystemServerSocketFd); + fds_to_ignore.push_back(gSystemServerSocketFd); + } + + pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, @@ -1397,9 +1480,15 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( fds_to_ignore.push_back(gUsapPoolEventFD); } + if (gSystemServerSocketFd != -1) { + fds_to_close.push_back(gSystemServerSocketFd); + fds_to_ignore.push_back(gSystemServerSocketFd); + } + pid_t pid = ForkCommon(env, true, fds_to_close, - fds_to_ignore); + fds_to_ignore, + true); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities, @@ -1441,13 +1530,15 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( * zygote in managed code. * @param managed_session_socket_fds A list of anonymous session sockets that must be ignored by * the FD hygiene code and automatically "closed" in the new USAP. + * @param is_priority_fork Controls the nice level assigned to the newly created process * @return */ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, jclass, jint read_pipe_fd, jint write_pipe_fd, - jintArray managed_session_socket_fds) { + jintArray managed_session_socket_fds, + jboolean is_priority_fork) { std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()), fds_to_ignore(fds_to_close); @@ -1461,6 +1552,9 @@ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, fds_to_close.push_back(gZygoteSocketFD); fds_to_close.push_back(gUsapPoolEventFD); fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end()); + if (gSystemServerSocketFd != -1) { + fds_to_close.push_back(gSystemServerSocketFd); + } fds_to_ignore.push_back(gZygoteSocketFD); fds_to_ignore.push_back(gUsapPoolSocketFD); @@ -1468,8 +1562,12 @@ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, fds_to_ignore.push_back(read_pipe_fd); fds_to_ignore.push_back(write_pipe_fd); fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end()); + if (gSystemServerSocketFd != -1) { + fds_to_ignore.push_back(gSystemServerSocketFd); + } - pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore); + pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore, + is_priority_fork == JNI_TRUE); if (usap_pid != 0) { ++gUsapPoolCount; @@ -1567,6 +1665,7 @@ static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jc ALOGE("Unable to fetch USAP pool socket file descriptor"); } + initUnsolSocketToSystemServer(); /* * Security Initialization */ @@ -1706,6 +1805,48 @@ static void com_android_internal_os_Zygote_nativeUnblockSigTerm(JNIEnv* env, jcl UnblockSignal(SIGTERM, fail_fn); } +static void com_android_internal_os_Zygote_nativeBoostUsapPriority(JNIEnv* env, jclass) { + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); +} + +static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclass, jbyteArray in, + jint length, jintArray out) { + if (length != sizeof(struct UnsolicitedZygoteMessageSigChld)) { + // Apparently it's not the message we are expecting. + return -1; + } + if (in == nullptr || out == nullptr) { + // Invalid parameter + jniThrowException(env, "java/lang/IllegalArgumentException", nullptr); + return -1; + } + ScopedByteArrayRO source(env, in); + if (source.size() < length) { + // Invalid parameter + jniThrowException(env, "java/lang/IllegalArgumentException", nullptr); + return -1; + } + const struct UnsolicitedZygoteMessageSigChld* msg = + reinterpret_cast<const struct UnsolicitedZygoteMessageSigChld*>(source.get()); + + switch (msg->header.type) { + case UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD: { + ScopedIntArrayRW buf(env, out); + if (buf.size() != 3) { + jniThrowException(env, "java/lang/IllegalArgumentException", nullptr); + return UNSOLICITED_ZYGOTE_MESSAGE_TYPE_RESERVED; + } + buf[0] = msg->payload.pid; + buf[1] = msg->payload.uid; + buf[2] = msg->payload.status; + return 3; + } + default: + break; + } + return -1; +} + static const JNINativeMethod gMethods[] = { { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I", @@ -1718,7 +1859,7 @@ static const JNINativeMethod gMethods[] = { (void *) com_android_internal_os_Zygote_nativePreApplicationInit }, { "nativeInstallSeccompUidGidFilter", "(II)V", (void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter }, - { "nativeForkUsap", "(II[I)I", + { "nativeForkUsap", "(II[IZ)I", (void *) com_android_internal_os_Zygote_nativeForkUsap }, { "nativeSpecializeAppProcess", "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V", @@ -1740,7 +1881,11 @@ static const JNINativeMethod gMethods[] = { { "nativeBlockSigTerm", "()V", (void* ) com_android_internal_os_Zygote_nativeBlockSigTerm }, { "nativeUnblockSigTerm", "()V", - (void* ) com_android_internal_os_Zygote_nativeUnblockSigTerm } + (void* ) com_android_internal_os_Zygote_nativeUnblockSigTerm }, + { "nativeBoostUsapPriority", "()V", + (void* ) com_android_internal_os_Zygote_nativeBoostUsapPriority }, + {"nativeParseSigChld", "([BI[I)I", + (void* ) com_android_internal_os_Zygote_nativeParseSigChld}, }; int register_com_android_internal_os_Zygote(JNIEnv* env) { diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index c8e901e1e15e..1b6d622e917e 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -33,25 +33,23 @@ // Static whitelist of open paths that the zygote is allowed to keep open. static const char* kPathWhitelist[] = { - "/apex/com.android.conscrypt/javalib/conscrypt.jar", - "/apex/com.android.ipsec/javalib/ike.jar", - "/apex/com.android.media/javalib/updatable-media.jar", - "/apex/com.android.sdkext/javalib/framework-sdkext.jar", - "/apex/com.android.telephony/javalib/telephony-common.jar", - "/apex/com.android.telephony/javalib/ims-common.jar", - "/apex/com.android.tethering/javalib/framework-tethering.jar", - "/dev/null", - "/dev/socket/zygote", - "/dev/socket/zygote_secondary", - "/dev/socket/usap_pool_primary", - "/dev/socket/usap_pool_secondary", - "/dev/socket/webview_zygote", - "/dev/socket/heapprofd", - "/sys/kernel/debug/tracing/trace_marker", - "/system/framework/framework-res.apk", - "/dev/urandom", - "/dev/ion", - "/dev/dri/renderD129", // Fixes b/31172436 + "/apex/com.android.conscrypt/javalib/conscrypt.jar", + "/apex/com.android.ipsec/javalib/ike.jar", + "/apex/com.android.media/javalib/updatable-media.jar", + "/apex/com.android.sdkext/javalib/framework-sdkextensions.jar", + "/apex/com.android.tethering/javalib/framework-tethering.jar", + "/dev/null", + "/dev/socket/zygote", + "/dev/socket/zygote_secondary", + "/dev/socket/usap_pool_primary", + "/dev/socket/usap_pool_secondary", + "/dev/socket/webview_zygote", + "/dev/socket/heapprofd", + "/sys/kernel/debug/tracing/trace_marker", + "/system/framework/framework-res.apk", + "/dev/urandom", + "/dev/ion", + "/dev/dri/renderD129", // Fixes b/31172436 }; static const char kFdPath[] = "/proc/self/fd"; diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 28733798b9ad..7452f809a14d 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -232,6 +232,8 @@ message ConstantsProto { // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't // ready now. optional bool skip_not_ready_jobs = 1; + // Whether or not TimeController will use a non-wakeup alarm for delay constraints. + optional bool use_non_wakeup_alarm_for_delay = 2; } optional TimeController time_controller = 25; diff --git a/core/proto/android/stats/otaupdate/updateengine_enums.proto b/core/proto/android/stats/otaupdate/updateengine_enums.proto new file mode 100644 index 000000000000..a6e9919ba606 --- /dev/null +++ b/core/proto/android/stats/otaupdate/updateengine_enums.proto @@ -0,0 +1,82 @@ +/* + * 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 = "proto2"; +package android.stats.otaupdate; + +// The payload type of an OTA update attempt on A/B devices. +enum PayloadType { + FULL = 10000; + DELTA = 10001; +} + +// The attempt result reported by the update engine for an OTA update. +enum AttemptResult { + UPDATE_SUCCEEDED = 10000; + INTERNAL_ERROR = 10001; + PAYLOAD_DOWNLOAD_ERROR = 10002; + METADATA_MALFORMED = 10003; + OPERATION_MALFORMED = 10004; + OPERATION_EXECUTION_ERROR = 10005; + METADATA_VERIFICATION_FAILED = 10006; + PAYLOAD_VERIFICATION_FAILED = 10007; + VERIFICATION_FAILED = 10008; + POSTINSTALL_FAILED = 10009; + ABNORMAL_TERMINATION = 10010; + UPDATE_CANCELED = 10011; + UPDATE_SUCCEEDED_NOT_ACTIVE = 10012; +} + +// The error code reported by the update engine after an OTA update attempt +// on A/B devices. More details in system/update_engine/common/error_code.h +enum ErrorCode { + SUCCESS = 10000; + ERROR = 10001; + FILESYSTEM_COPIER_ERROR = 10004; + POST_INSTALL_RUNNER_ERROR = 10005; + PAYLOAD_MISMATCHED_TYPE_ERROR = 10006; + INSTALL_DEVICE_OPEN_ERROR = 10007; + KERNEL_DEVICE_OPEN_ERROR = 10008; + DOWNLOAD_TRANSFER_ERROR = 10009; + PAYLOAD_HASH_MISMATCH_ERROR = 10010; + PAYLOAD_SIZE_MISMATCH_ERROR = 10011; + DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 10012; + DOWNLOAD_NEW_PARTITION_INFO_ERROR = 10013; + DOWNLOAD_WRITE_ERROR = 10014; + NEW_ROOTFS_VERIFICATION_ERROR = 10015; + SIGNED_DELTA_PAYLOAD_EXPECTED_ERROR = 10017; + DOWNLOAD_PAYLOAD_PUB_KEY_VERIFICATION_ERROR = 10018; + DOWNLOAD_STATE_INITIALIZATION_ERROR = 10020; + DOWNLOAD_INVALID_METADATA_MAGIC_STRING = 10021; + DOWNLOAD_SIGNATURE_MISSING_IN_MANIFEST = 10022; + DOWNLOAD_MANIFEST_PARSE_ERROR = 10023; + DOWNLOAD_METADATA_SIGNATURE_ERROR = 10024; + DOWNLOAD_METADATA_SIGNATURE_VERIFICATION_ERROR = 10025; + DOWNLOAD_METADATA_SIGNATURE_MISMATCH = 10026; + DOWNLOAD_OPERATION_HASH_VERIFICATION_ERROR = 10027; + DOWNLOAD_OPERATION_EXECUTION_ERROR = 10028; + DOWNLOAD_OPERATION_HASH_MISMATCH = 10029; + DOWNLOAD_INVALID_METADATA_SIZE = 10032; + DOWNLOAD_INVALID_METADATA_SIGNATURE = 10033; + DOWNLOAD_OPERATION_HASH_MISSING_ERROR = 10038; + DOWNLOAD_METADATA_SIGNATURE_MISSING_ERROR = 10039; + UNSUPPORTED_MAJOR_PAYLOAD_VERSION = 10044; + UNSUPPORTED_MINOR_PAYLOAD_VERSION = 10045; + FILESYSTEM_VERIFIER_ERROR = 10047; + USER_CANCELED = 10048; + PAYLOAD_TIMESTAMP_ERROR = 10051; + UPDATED_BUT_NOT_ACTIVE = 10052; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 31ac2bc7407f..5c204aba49a1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -451,7 +451,6 @@ <protected-broadcast android:name="android.intent.action.internal_sim_state_changed" /> <protected-broadcast android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> <protected-broadcast android:name="android.intent.action.PRECISE_CALL_STATE" /> - <protected-broadcast android:name="android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.intent.action.SUBSCRIPTION_PHONE_STATE" /> <protected-broadcast android:name="android.intent.action.USER_INFO_CHANGED" /> <protected-broadcast android:name="android.intent.action.USER_UNLOCKED" /> @@ -557,10 +556,12 @@ <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" /> - <protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" /> + <protected-broadcast android:name="android.net.sip.action.SIP_INCOMING_CALL" /> <protected-broadcast android:name="com.android.phone.SIP_ADD_PHONE" /> - <protected-broadcast android:name="com.android.phone.SIP_REMOVE_PHONE" /> - <protected-broadcast android:name="com.android.phone.SIP_CALL_OPTION_CHANGED" /> + <protected-broadcast android:name="android.net.sip.action.SIP_REMOVE_PROFILE" /> + <protected-broadcast android:name="android.net.sip.action.SIP_SERVICE_UP" /> + <protected-broadcast android:name="android.net.sip.action.SIP_CALL_OPTION_CHANGED" /> + <protected-broadcast android:name="android.net.sip.action.START_SIP" /> <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_CONNECTED" /> <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED" /> @@ -634,10 +635,6 @@ <protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" /> - <!-- NETWORK_SET_TIME moved from com.android.phone to system server. It should ultimately be - removed. --> - <protected-broadcast android:name="android.telephony.action.NETWORK_SET_TIME" /> - <!-- For tether entitlement recheck--> <protected-broadcast android:name="com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM" /> @@ -721,6 +718,11 @@ <!-- ====================================================================== --> <eat-comment /> + <!-- @SystemApi Allows accessing the messages on ICC + @hide Used internally. --> + <permission android:name="android.permission.ACCESS_MESSAGES_ON_ICC" + android:protectionLevel="signature|telephony" /> + <!-- Used for runtime permissions related to user's SMS messages. --> <permission-group android:name="android.permission-group.SMS" android:icon="@drawable/perm_group_sms" @@ -1778,6 +1780,11 @@ android:label="@string/permlab_preferredPaymentInfo" android:protectionLevel="normal" /> + <!-- @SystemApi Allows an internal user to use privileged SecureElement APIs. + @hide --> + <permission android:name="android.permission.SECURE_ELEMENT_PRIVILEGED" + android:protectionLevel="signature|privileged" /> + <!-- @deprecated This permission used to allow too broad access to sensitive methods and all its uses have been replaced by a more appropriate permission. Most uses have been replaced with a NETWORK_STACK or NETWORK_SETTINGS check. Please look up the documentation of the @@ -2058,8 +2065,10 @@ android:protectionLevel="signature|privileged" /> <!-- Allows read only access to precise phone state. - @hide Pending API council approval --> + Allows reading of detailed information about phone state for special-use applications + such as dialers, carrier applications, or ims applications. --> <permission android:name="android.permission.READ_PRECISE_PHONE_STATE" + android:permissionGroup="android.permission-group.UNDEFINED" android:protectionLevel="signature|privileged" /> <!-- @SystemApi Allows read access to privileged phone state. @@ -2524,17 +2533,17 @@ <permission android:name="android.permission.READ_WALLPAPER_INTERNAL" android:protectionLevel="signature|privileged" /> - <!-- ============================================ --> - <!-- Permissions for changing the system clock --> - <!-- ============================================ --> + <!-- ===================================================== --> + <!-- Permissions for changing the system clock / time zone --> + <!-- ===================================================== --> <eat-comment /> - <!-- Allows applications to set the system time. - <p>Not for use by third-party applications. --> + <!-- Allows applications to set the system time directly. + <p>Not for use by third-party applications. --> <permission android:name="android.permission.SET_TIME" android:protectionLevel="signature|privileged" /> - <!-- Allows applications to set the system time zone. + <!-- Allows applications to set the system time zone directly. <p>Not for use by third-party applications. --> <permission android:name="android.permission.SET_TIME_ZONE" @@ -2542,6 +2551,20 @@ android:description="@string/permdesc_setTimeZone" android:protectionLevel="signature|privileged" /> + <!-- Allows telephony to suggest the time / time zone. + <p>Not for use by third-party applications. + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @hide + --> + <permission android:name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE" + android:protectionLevel="signature|telephony" /> + + <!-- Allows applications like settings to suggest the user's manually chosen time / time zone. + <p>Not for use by third-party applications. + @hide + --> + <permission android:name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE" + android:protectionLevel="signature" /> + <!-- ==================================================== --> <!-- Permissions related to changing status bar --> <!-- ==================================================== --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a404e2ed6f52..04d1eef9cba1 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2266,9 +2266,6 @@ <!-- Number of times to try again with the shorter interval, before backing off until the normal polling interval. A value < 0 indicates infinite. --> <integer name="config_ntpRetry">3</integer> - <!-- If the time difference is greater than this threshold in milliseconds, - then update the time. --> - <integer name="config_ntpThreshold">5000</integer> <!-- Timeout to wait for NTP server response in milliseconds. --> <integer name="config_ntpTimeout">5000</integer> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 4aa44fc6ebaa..9bc0d969aed9 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5393,6 +5393,10 @@ <!-- Description of media type: presentation file, such as PPT. The 'extension' variable is the file name extension. [CHAR LIMIT=32] --> <string name="mime_type_presentation_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> presentation</string> + <!-- Strings for Bluetooth service --> + <!-- toast message informing user that Bluetooth stays on after airplane mode is turned on. [CHAR LIMIT=NONE] --> + <string name="bluetooth_airplane_mode_toast">Bluetooth will stay on during airplane mode</string> + <!-- Strings for car --> <!-- String displayed when loading a user in the car [CHAR LIMIT=30] --> <string name="car_loading_profile">Loading</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 2507787e2847..cd43e9fca526 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -489,7 +489,6 @@ <java-symbol type="integer" name="config_ntpPollingInterval" /> <java-symbol type="integer" name="config_ntpPollingIntervalShorter" /> <java-symbol type="integer" name="config_ntpRetry" /> - <java-symbol type="integer" name="config_ntpThreshold" /> <java-symbol type="integer" name="config_ntpTimeout" /> <java-symbol type="integer" name="config_shortPressOnPowerBehavior" /> <java-symbol type="integer" name="config_toastDefaultGravity" /> @@ -3796,6 +3795,9 @@ <java-symbol type="string" name="mime_type_presentation" /> <java-symbol type="string" name="mime_type_presentation_ext" /> + <!-- For Bluetooth service --> + <java-symbol type="string" name="bluetooth_airplane_mode_toast" /> + <!-- For high refresh rate displays --> <java-symbol type="integer" name="config_defaultPeakRefreshRate" /> <java-symbol type="integer" name="config_defaultRefreshRateInZone" /> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java index f0a83678f70b..a296ca27e268 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java @@ -16,6 +16,7 @@ package com.android.connectivitymanagertest; +import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; @@ -136,7 +137,7 @@ public class WifiConfigurationHelper { config.enterpriseConfig.setPhase2Method(phase2); config.enterpriseConfig.setIdentity(identity); config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity); - config.enterpriseConfig.setCaCertificateAlias(caCert); + config.enterpriseConfig.setCaCertificateAliases(new String[] {caCert}); config.enterpriseConfig.setClientCertificateAlias(clientCert); return config; } @@ -147,8 +148,12 @@ public class WifiConfigurationHelper { private static WifiConfiguration createGenericConfig(String ssid) { WifiConfiguration config = new WifiConfiguration(); config.SSID = quotedString(ssid); - config.setIpAssignment(IpAssignment.DHCP); - config.setProxySettings(ProxySettings.NONE); + + IpConfiguration ipConfiguration = config.getIpConfiguration(); + ipConfiguration.setIpAssignment(IpAssignment.DHCP); + ipConfiguration.setProxySettings(ProxySettings.NONE); + config.setIpConfiguration(ipConfiguration); + return config; } @@ -237,6 +242,7 @@ public class WifiConfigurationHelper { throw new IllegalArgumentException(); } + IpConfiguration ipConfiguration = config.getIpConfiguration(); if (jsonConfig.has("ip")) { StaticIpConfiguration staticIpConfig = new StaticIpConfiguration(); @@ -247,13 +253,14 @@ public class WifiConfigurationHelper { staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns1"))); staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns2"))); - config.setIpAssignment(IpAssignment.STATIC); - config.setStaticIpConfiguration(staticIpConfig); + ipConfiguration.setIpAssignment(IpAssignment.STATIC); + ipConfiguration.setStaticIpConfiguration(staticIpConfig); } else { - config.setIpAssignment(IpAssignment.DHCP); + ipConfiguration.setIpAssignment(IpAssignment.DHCP); } + ipConfiguration.setProxySettings(ProxySettings.NONE); + config.setIpConfiguration(ipConfiguration); - config.setProxySettings(ProxySettings.NONE); return config; } diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java index 2989df83866c..5d42915fc82b 100644 --- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java +++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java @@ -268,7 +268,7 @@ public class BandwidthTest extends InstrumentationTestCase { File snd_stat = new File (root_filepath + "tcp_snd"); int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat); NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); - stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT, + stats.addEntry(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT, NetworkStats.TAG_NONE, rx, 0, tx, 0, 0); return stats; } diff --git a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java index 707d7b30e09b..239f971664e9 100644 --- a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java +++ b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java @@ -54,7 +54,7 @@ public class NetworkStatsBenchmark { recycle.txBytes = 150000; recycle.txPackets = 1500; recycle.operations = 0; - mNetworkStats.addValues(recycle); + mNetworkStats.addEntry(recycle); if (recycle.set == 1) { uid++; } @@ -70,7 +70,7 @@ public class NetworkStatsBenchmark { recycle.txBytes = 180000 * mSize; recycle.txPackets = 1200 * mSize; recycle.operations = 0; - mNetworkStats.addValues(recycle); + mNetworkStats.addEntry(recycle); } } diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java index 68b9b0079761..f4709ff0bc00 100644 --- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java @@ -33,14 +33,15 @@ import android.os.ParcelFileDescriptor.AutoCloseInputStream; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.support.test.uiautomator.UiDevice; import android.test.InstrumentationTestCase; import android.util.Log; -import libcore.io.Streams; - import com.google.mockwebserver.MockResponse; import com.google.mockwebserver.MockWebServer; +import libcore.io.Streams; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -63,6 +64,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { private static final String TAG = "DownloadManagerBaseTest"; protected DownloadManager mDownloadManager = null; private MockWebServer mServer = null; + private UiDevice mUiDevice = null; protected String mFileType = "text/plain"; protected Context mContext = null; protected MultipleDownloadsCompletedReceiver mReceiver = null; @@ -234,6 +236,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { @Override public void setUp() throws Exception { mContext = getInstrumentation().getContext(); + mUiDevice = UiDevice.getInstance(getInstrumentation()); mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE); mServer = new MockWebServer(); mServer.play(); @@ -512,7 +515,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { Log.i(LOG_TAG, "Setting WiFi State to: " + enable); WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE); - manager.setWifiEnabled(enable); + mUiDevice.executeShellCommand("svc wifi " + (enable ? "enable" : "disable")); String timeoutMessage = "Timed out waiting for Wifi to be " + (enable ? "enabled!" : "disabled!"); diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java index de6f8f7231fa..750ffa1c9a54 100644 --- a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java @@ -22,7 +22,7 @@ import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcel import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import android.util.TimestampedValue; +import android.os.TimestampedValue; import org.junit.Test; diff --git a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java new file mode 100644 index 000000000000..b88c36f20bc6 --- /dev/null +++ b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 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.app.timedetector; + +import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable; +import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.os.TimestampedValue; + +import org.junit.Test; + +public class NetworkTimeSuggestionTest { + + private static final TimestampedValue<Long> ARBITRARY_TIME = + new TimestampedValue<>(1111L, 2222L); + + @Test + public void testEquals() { + NetworkTimeSuggestion one = new NetworkTimeSuggestion(ARBITRARY_TIME); + assertEquals(one, one); + + NetworkTimeSuggestion two = new NetworkTimeSuggestion(ARBITRARY_TIME); + assertEquals(one, two); + assertEquals(two, one); + + TimestampedValue<Long> differentTime = new TimestampedValue<>( + ARBITRARY_TIME.getReferenceTimeMillis() + 1, + ARBITRARY_TIME.getValue()); + NetworkTimeSuggestion three = new NetworkTimeSuggestion(differentTime); + assertNotEquals(one, three); + assertNotEquals(three, one); + + // DebugInfo must not be considered in equals(). + one.addDebugInfo("Debug info 1"); + two.addDebugInfo("Debug info 2"); + assertEquals(one, two); + } + + @Test + public void testParcelable() { + NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(ARBITRARY_TIME); + assertRoundTripParcelable(suggestion); + + // DebugInfo should also be stored (but is not checked by equals() + suggestion.addDebugInfo("This is debug info"); + NetworkTimeSuggestion rtSuggestion = roundTripParcelable(suggestion); + assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo()); + } +} diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java index bee270e5f5c9..ba29a97b55ab 100644 --- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java @@ -22,7 +22,7 @@ import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcel import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import android.util.TimestampedValue; +import android.os.TimestampedValue; import org.junit.Test; diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java index c6c0b46d0505..b13bcd1311f6 100644 --- a/core/tests/coretests/src/android/net/NetworkKeyTest.java +++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java @@ -18,6 +18,7 @@ package android.net; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.net.wifi.ScanResult; @@ -107,7 +108,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_nullSsid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.BSSID = VALID_BSSID; assertNull(NetworkKey.createFromScanResult(scanResult)); @@ -115,7 +116,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_emptySsid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = ""; scanResult.BSSID = VALID_BSSID; @@ -124,7 +125,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_noneSsid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = WifiManager.UNKNOWN_SSID; scanResult.BSSID = VALID_BSSID; @@ -133,7 +134,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_nullBssid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = VALID_UNQUOTED_SSID; assertNull(NetworkKey.createFromScanResult(scanResult)); @@ -141,7 +142,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_emptyBssid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = VALID_UNQUOTED_SSID; scanResult.BSSID = ""; @@ -150,7 +151,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_invalidBssid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = VALID_UNQUOTED_SSID; scanResult.BSSID = INVALID_BSSID; @@ -159,7 +160,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_validSsid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = VALID_UNQUOTED_SSID; scanResult.BSSID = VALID_BSSID; diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/os/TimestampedValueTest.java index 6fc2400316c2..f36d9e6b1eff 100644 --- a/core/tests/coretests/src/android/util/TimestampedValueTest.java +++ b/core/tests/coretests/src/android/os/TimestampedValueTest.java @@ -14,14 +14,12 @@ * limitations under the License. */ -package android.util; +package android.os; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.fail; -import android.os.Parcel; - import androidx.test.runner.AndroidJUnit4; import org.junit.Test; diff --git a/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java b/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java new file mode 100644 index 000000000000..b605520c659d --- /dev/null +++ b/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java @@ -0,0 +1,120 @@ +/* + * 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.text.format; + +import static org.junit.Assert.assertEquals; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Locale; +import java.util.TimeZone; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TimeMigrationUtilsTest { + + private static final int ONE_DAY_IN_SECONDS = 24 * 60 * 60; + + private Locale mDefaultLocale; + private TimeZone mDefaultTimeZone; + + @Before + public void setUp() { + mDefaultLocale = Locale.getDefault(); + mDefaultTimeZone = TimeZone.getDefault(); + } + + @After + public void tearDown() { + Locale.setDefault(mDefaultLocale); + TimeZone.setDefault(mDefaultTimeZone); + } + + @Test + public void formatMillisWithFixedFormat_fixes2038Issue() { + Locale.setDefault(Locale.UK); + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + + // The following cannot be represented properly using Time because they are outside of the + // supported range. + long y2038Issue1 = (((long) Integer.MIN_VALUE) - ONE_DAY_IN_SECONDS) * 1000L; + assertEquals( + "1901-12-12 20:45:52", TimeMigrationUtils.formatMillisWithFixedFormat(y2038Issue1)); + long y2038Issue2 = (((long) Integer.MAX_VALUE) + ONE_DAY_IN_SECONDS) * 1000L; + assertEquals( + "2038-01-20 03:14:07", TimeMigrationUtils.formatMillisWithFixedFormat(y2038Issue2)); + } + + /** + * Compares TimeMigrationUtils.formatSimpleDateTime() with the code it is replacing. + */ + @Test + public void formatMillisAsDateTime_matchesOldBehavior() { + // A selection of interesting locales. + Locale[] locales = new Locale[] { + Locale.US, + Locale.UK, + Locale.FRANCE, + Locale.JAPAN, + Locale.CHINA, + // Android supports RTL locales like arabic and arabic with latin numbers. + Locale.forLanguageTag("ar-AE"), + Locale.forLanguageTag("ar-AE-u-nu-latn"), + }; + // A selection of interesting time zones. + String[] timeZoneIds = new String[] { + "UTC", "Europe/London", "America/New_York", "America/Los_Angeles", "Asia/Shanghai", + }; + // Some arbitrary times when the two formatters should agree. + long[] timesMillis = new long[] { + System.currentTimeMillis(), + 0, + // The Time class only works in 32-bit range, the replacement works beyond that. To + // avoid messing around with offsets and complicating the test, below there are a + // day after / before the known limits. + (Integer.MIN_VALUE + ONE_DAY_IN_SECONDS) * 1000L, + (Integer.MAX_VALUE - ONE_DAY_IN_SECONDS) * 1000L, + }; + + for (Locale locale : locales) { + Locale.setDefault(locale); + for (String timeZoneId : timeZoneIds) { + TimeZone timeZone = TimeZone.getTimeZone(timeZoneId); + TimeZone.setDefault(timeZone); + for (long timeMillis : timesMillis) { + Time time = new Time(); + time.set(timeMillis); + String oldResult = time.format("%Y-%m-%d %H:%M:%S"); + String newResult = TimeMigrationUtils.formatMillisWithFixedFormat(timeMillis); + assertEquals( + "locale=" + locale + ", timeZoneId=" + timeZoneId + + ", timeMillis=" + timeMillis, + oldResult, newResult); + } + } + } + } +} diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/core/tests/coretests/src/android/util/StatsEventTest.java new file mode 100644 index 000000000000..ac25e2734ac9 --- /dev/null +++ b/core/tests/coretests/src/android/util/StatsEventTest.java @@ -0,0 +1,474 @@ +/* + * 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.util; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.os.SystemClock; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.google.common.collect.Range; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Internal tests for {@link StatsEvent}. + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class StatsEventTest { + + @Test + public void testNoFields() { + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder().usePooledBuffer().build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + final int expectedAtomId = 0; + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(3); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("Third element is not errors type") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS); + + final int errorMask = buffer.getInt(); + + assertWithMessage("ERROR_NO_ATOM_ID should be the only error in the error mask") + .that(errorMask).isEqualTo(StatsEvent.ERROR_NO_ATOM_ID); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testIntBooleanIntInt() { + final int expectedAtomId = 109; + final int field1 = 1; + final boolean field2 = true; + final int field3 = 3; + final int field4 = 4; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeInt(field1) + .writeBoolean(field2) + .writeInt(field3) + .writeInt(field4) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(6); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 1") + .that(buffer.getInt()).isEqualTo(field1); + + assertWithMessage("Second field is not Boolean") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); + + assertWithMessage("Incorrect field 2") + .that(buffer.get()).isEqualTo(1); + + assertWithMessage("Third field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 3") + .that(buffer.getInt()).isEqualTo(field3); + + assertWithMessage("Fourth field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 4") + .that(buffer.getInt()).isEqualTo(field4); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testStringFloatByteArray() { + final int expectedAtomId = 109; + final String field1 = "Str 1"; + final float field2 = 9.334f; + final byte[] field3 = new byte[] { 56, 23, 89, -120 }; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeString(field1) + .writeFloat(field2) + .writeByteArray(field3) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(5); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not String") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING); + + final String field1Actual = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect field 1") + .that(field1Actual).isEqualTo(field1); + + assertWithMessage("Second field is not Float") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT); + + assertWithMessage("Incorrect field 2") + .that(buffer.getFloat()).isEqualTo(field2); + + assertWithMessage("Third field is not byte array") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BYTE_ARRAY); + + final byte[] field3Actual = getByteArrayFromByteBuffer(buffer); + assertWithMessage("Incorrect field 3") + .that(field3Actual).isEqualTo(field3); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testAttributionChainLong() { + final int expectedAtomId = 109; + final int[] uids = new int[] { 1, 2, 3, 4, 5 }; + final String[] tags = new String[] { "1", "2", "3", "4", "5" }; + final long field2 = -230909823L; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeAttributionChain(uids, tags) + .writeLong(field2) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(4); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not Attribution Chain") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ATTRIBUTION_CHAIN); + + assertWithMessage("Incorrect number of attribution nodes") + .that(buffer.get()).isEqualTo((byte) uids.length); + + for (int i = 0; i < tags.length; i++) { + assertWithMessage("Incorrect uid in Attribution Chain") + .that(buffer.getInt()).isEqualTo(uids[i]); + + final String tag = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect tag in Attribution Chain") + .that(tag).isEqualTo(tags[i]); + } + + assertWithMessage("Second field is not Long") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect field 2") + .that(buffer.getLong()).isEqualTo(field2); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testKeyValuePairs() { + final int expectedAtomId = 109; + final SparseIntArray intMap = new SparseIntArray(); + final SparseLongArray longMap = new SparseLongArray(); + final SparseArray<String> stringMap = new SparseArray<>(); + final SparseArray<Float> floatMap = new SparseArray<>(); + intMap.put(1, -1); + intMap.put(2, -2); + stringMap.put(3, "abc"); + stringMap.put(4, "2h"); + floatMap.put(9, -234.344f); + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeKeyValuePairs(intMap, longMap, stringMap, floatMap) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(3); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not KeyValuePairs") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_KEY_VALUE_PAIRS); + + assertWithMessage("Incorrect number of key value pairs") + .that(buffer.get()).isEqualTo( + (byte) (intMap.size() + longMap.size() + stringMap.size() + + floatMap.size())); + + for (int i = 0; i < intMap.size(); i++) { + assertWithMessage("Incorrect key in intMap") + .that(buffer.getInt()).isEqualTo(intMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_INT in intMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("Incorrect value in intMap") + .that(buffer.getInt()).isEqualTo(intMap.valueAt(i)); + } + + for (int i = 0; i < longMap.size(); i++) { + assertWithMessage("Incorrect key in longMap") + .that(buffer.getInt()).isEqualTo(longMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_LONG in longMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + assertWithMessage("Incorrect value in longMap") + .that(buffer.getLong()).isEqualTo(longMap.valueAt(i)); + } + + for (int i = 0; i < stringMap.size(); i++) { + assertWithMessage("Incorrect key in stringMap") + .that(buffer.getInt()).isEqualTo(stringMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_STRING in stringMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING); + final String value = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect value in stringMap") + .that(value).isEqualTo(stringMap.valueAt(i)); + } + + for (int i = 0; i < floatMap.size(); i++) { + assertWithMessage("Incorrect key in floatMap") + .that(buffer.getInt()).isEqualTo(floatMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_FLOAT in floatMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT); + assertWithMessage("Incorrect value in floatMap") + .that(buffer.getFloat()).isEqualTo(floatMap.valueAt(i)); + } + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testSingleAnnotations() { + final int expectedAtomId = 109; + final int field1 = 1; + final byte field1AnnotationId = 45; + final boolean field1AnnotationValue = false; + final boolean field2 = true; + final byte field2AnnotationId = 1; + final int field2AnnotationValue = 23; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeInt(field1) + .addBooleanAnnotation(field1AnnotationId, field1AnnotationValue) + .writeBoolean(field2) + .addIntAnnotation(field2AnnotationId, field2AnnotationValue) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(4); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + final byte field1Header = buffer.get(); + final int field1AnnotationValueCount = field1Header >> 4; + final byte field1Type = (byte) (field1Header & 0x0F); + assertWithMessage("First field is not Int") + .that(field1Type).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("First field annotation count is wrong") + .that(field1AnnotationValueCount).isEqualTo(1); + assertWithMessage("Incorrect field 1") + .that(buffer.getInt()).isEqualTo(field1); + assertWithMessage("First field's annotation id is wrong") + .that(buffer.get()).isEqualTo(field1AnnotationId); + assertWithMessage("First field's annotation type is wrong") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); + assertWithMessage("First field's annotation value is wrong") + .that(buffer.get()).isEqualTo(field1AnnotationValue ? 1 : 0); + + final byte field2Header = buffer.get(); + final int field2AnnotationValueCount = field2Header >> 4; + final byte field2Type = (byte) (field2Header & 0x0F); + assertWithMessage("Second field is not boolean") + .that(field2Type).isEqualTo(StatsEvent.TYPE_BOOLEAN); + assertWithMessage("Second field annotation count is wrong") + .that(field2AnnotationValueCount).isEqualTo(1); + assertWithMessage("Incorrect field 2") + .that(buffer.get()).isEqualTo(field2 ? 1 : 0); + assertWithMessage("Second field's annotation id is wrong") + .that(buffer.get()).isEqualTo(field2AnnotationId); + assertWithMessage("Second field's annotation type is wrong") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("Second field's annotation value is wrong") + .that(buffer.getInt()).isEqualTo(field2AnnotationValue); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + private static byte[] getByteArrayFromByteBuffer(final ByteBuffer buffer) { + final int numBytes = buffer.getInt(); + byte[] bytes = new byte[numBytes]; + buffer.get(bytes); + return bytes; + } + + private static String getStringFromByteBuffer(final ByteBuffer buffer) { + final byte[] bytes = getByteArrayFromByteBuffer(buffer); + return new String(bytes, UTF_8); + } +} diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp new file mode 100644 index 000000000000..a2fcef56b780 --- /dev/null +++ b/core/tests/overlaytests/host/Android.bp @@ -0,0 +1,30 @@ +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +java_test_host { + name: "OverlayHostTests", + srcs: ["src/**/*.java"], + libs: ["tradefed"], + test_suites: ["general-tests"], + target_required: [ + "OverlayHostTests_NonPlatformSignatureOverlay", + "OverlayHostTests_PlatformSignatureStaticOverlay", + "OverlayHostTests_PlatformSignatureOverlay", + "OverlayHostTests_UpdateOverlay", + "OverlayHostTests_FrameworkOverlayV1", + "OverlayHostTests_FrameworkOverlayV2", + "OverlayHostTests_AppOverlayV1", + "OverlayHostTests_AppOverlayV2", + ], +} diff --git a/core/tests/overlaytests/host/Android.mk b/core/tests/overlaytests/host/Android.mk index e7348d52adfe..d58d9393c0b8 100644 --- a/core/tests/overlaytests/host/Android.mk +++ b/core/tests/overlaytests/host/Android.mk @@ -14,23 +14,6 @@ LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under,src) -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE := OverlayHostTests -LOCAL_JAVA_LIBRARIES := tradefed -LOCAL_COMPATIBILITY_SUITE := general-tests -LOCAL_TARGET_REQUIRED_MODULES := \ - OverlayHostTests_NonPlatformSignatureOverlay \ - OverlayHostTests_PlatformSignatureStaticOverlay \ - OverlayHostTests_PlatformSignatureOverlay \ - OverlayHostTests_UpdateOverlay \ - OverlayHostTests_FrameworkOverlayV1 \ - OverlayHostTests_FrameworkOverlayV2 \ - OverlayHostTests_AppOverlayV1 \ - OverlayHostTests_AppOverlayV2 -include $(BUILD_HOST_JAVA_LIBRARY) - # Include to build test-apps. include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java b/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java new file mode 100644 index 000000000000..556471260141 --- /dev/null +++ b/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java @@ -0,0 +1,286 @@ +/* + * 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.internal.util; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.os.Binder; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.HashMap; + +/** Unit tests for {@link ConnectivityUtil}. */ +public class ConnectivityUtilTest { + + public static final String TAG = "ConnectivityUtilTest"; + + // Mock objects for testing + @Mock private Context mMockContext; + @Mock private PackageManager mMockPkgMgr; + @Mock private ApplicationInfo mMockApplInfo; + @Mock private AppOpsManager mMockAppOps; + @Mock private UserManager mMockUserManager; + @Mock private LocationManager mLocationManager; + + private static final String TEST_PKG_NAME = "com.google.somePackage"; + private static final String TEST_FEATURE_ID = "com.google.someFeature"; + private static final int MANAGED_PROFILE_UID = 1100000; + private static final int OTHER_USER_UID = 1200000; + + private final String mInteractAcrossUsersFullPermission = + "android.permission.INTERACT_ACROSS_USERS_FULL"; + private final String mManifestStringCoarse = + Manifest.permission.ACCESS_COARSE_LOCATION; + private final String mManifestStringFine = + Manifest.permission.ACCESS_FINE_LOCATION; + + // Test variables + private int mWifiScanAllowApps; + private int mUid; + private int mCoarseLocationPermission; + private int mAllowCoarseLocationApps; + private int mFineLocationPermission; + private int mAllowFineLocationApps; + private int mCurrentUser; + private boolean mIsLocationEnabled; + private boolean mThrowSecurityException; + private Answer<Integer> mReturnPermission; + private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>(); + + private class TestConnectivityUtil extends ConnectivityUtil { + + TestConnectivityUtil(Context context) { + super(context); + } + + @Override + protected int getCurrentUser() { + return mCurrentUser; + } + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + initTestVars(); + } + + private void setupMocks() throws Exception { + when(mMockPkgMgr.getApplicationInfoAsUser(eq(TEST_PKG_NAME), eq(0), any())) + .thenReturn(mMockApplInfo); + when(mMockContext.getPackageManager()).thenReturn(mMockPkgMgr); + when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PKG_NAME)) + .thenReturn(mWifiScanAllowApps); + when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_COARSE_LOCATION), eq(mUid), + eq(TEST_PKG_NAME))) + .thenReturn(mAllowCoarseLocationApps); + when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(mUid), + eq(TEST_PKG_NAME))) + .thenReturn(mAllowFineLocationApps); + if (mThrowSecurityException) { + doThrow(new SecurityException("Package " + TEST_PKG_NAME + " doesn't belong" + + " to application bound to user " + mUid)) + .when(mMockAppOps).checkPackage(mUid, TEST_PKG_NAME); + } + when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)) + .thenReturn(mMockAppOps); + when(mMockContext.getSystemService(Context.USER_SERVICE)) + .thenReturn(mMockUserManager); + when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); + } + + private void setupTestCase() throws Exception { + setupMocks(); + setupMockInterface(); + } + + private void initTestVars() { + mPermissionsList.clear(); + mReturnPermission = createPermissionAnswer(); + mWifiScanAllowApps = AppOpsManager.MODE_ERRORED; + mUid = OTHER_USER_UID; + mThrowSecurityException = true; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M; + mIsLocationEnabled = false; + mCurrentUser = UserHandle.USER_SYSTEM; + mCoarseLocationPermission = PackageManager.PERMISSION_DENIED; + mFineLocationPermission = PackageManager.PERMISSION_DENIED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; + mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + } + + private void setupMockInterface() { + Binder.restoreCallingIdentity((((long) mUid) << 32) | Binder.getCallingPid()); + doAnswer(mReturnPermission).when(mMockContext).checkPermission( + anyString(), anyInt(), anyInt()); + when(mMockUserManager.isSameProfileGroup(UserHandle.SYSTEM.getIdentifier(), + UserHandle.getUserHandleForUid(MANAGED_PROFILE_UID).getIdentifier())) + .thenReturn(true); + when(mMockContext.checkPermission(mManifestStringCoarse, -1, mUid)) + .thenReturn(mCoarseLocationPermission); + when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) + .thenReturn(mFineLocationPermission); + when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); + } + + private Answer<Integer> createPermissionAnswer() { + return new Answer<Integer>() { + @Override + public Integer answer(InvocationOnMock invocation) { + int myUid = (int) invocation.getArguments()[1]; + String myPermission = (String) invocation.getArguments()[0]; + mPermissionsList.get(myPermission); + if (mPermissionsList.containsKey(myPermission)) { + int uid = mPermissionsList.get(myPermission); + if (myUid == uid) { + return PackageManager.PERMISSION_GRANTED; + } + } + return PackageManager.PERMISSION_DENIED; + } + }; + } + + @Test + public void testEnforceLocationPermission_HasAllPermissions_BeforeQ() throws Exception { + mIsLocationEnabled = true; + mThrowSecurityException = false; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mUid = mCurrentUser; + setupTestCase(); + new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + } + + @Test + public void testEnforceLocationPermission_HasAllPermissions_AfterQ() throws Exception { + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q; + mIsLocationEnabled = true; + mThrowSecurityException = false; + mUid = mCurrentUser; + mFineLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + } + + @Test + public void testEnforceLocationPermission_PkgNameAndUidMismatch() throws Exception { + mThrowSecurityException = true; + mIsLocationEnabled = true; + mFineLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_UserOrProfileNotCurrent() throws Exception { + mIsLocationEnabled = true; + mThrowSecurityException = false; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_NoCoarseLocationPermission() throws Exception { + mThrowSecurityException = false; + mIsLocationEnabled = true; + setupTestCase(); + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_NoFineLocationPermission() throws Exception { + mThrowSecurityException = false; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q; + mIsLocationEnabled = true; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + mUid = MANAGED_PROFILE_UID; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString()); + } + + @Test + public void testenforceCanAccessScanResults_LocationModeDisabled() throws Exception { + mThrowSecurityException = false; + mUid = MANAGED_PROFILE_UID; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid); + mIsLocationEnabled = false; + + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { + try { + r.run(); + Assert.fail("Expected " + exceptionClass + " to be thrown."); + } catch (Exception exception) { + assertTrue(exceptionClass.isInstance(exception)); + } + } +} diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd index 9520db767350..cc01a31224bc 100644 --- a/core/xsd/permission.xsd +++ b/core/xsd/permission.xsd @@ -126,12 +126,12 @@ </xs:complexType> <xs:complexType name="privapp-permissions"> <xs:sequence> - <xs:element name="permission" maxOccurs="unbounded"> + <xs:element name="permission" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:attribute name="name" type="xs:string"/> </xs:complexType> </xs:element> - <xs:element name="deny-permission" maxOccurs="unbounded"> + <xs:element name="deny-permission" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:attribute name="name" type="xs:string"/> </xs:complexType> @@ -141,12 +141,12 @@ </xs:complexType> <xs:complexType name="oem-permissions"> <xs:sequence> - <xs:element name="permission" maxOccurs="unbounded"> + <xs:element name="permission" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:attribute name="name" type="xs:string"/> </xs:complexType> </xs:element> - <xs:element name="deny-permission" maxOccurs="unbounded"> + <xs:element name="deny-permission" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:attribute name="name" type="xs:string"/> </xs:complexType> diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 4493f3a8dddc..0d12e1f7f83d 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -43,7 +43,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.carrierconfig", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.carrierconfig.xml", filename_from_src: true, @@ -67,7 +67,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.emergency", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.emergency.xml", filename_from_src: true, @@ -82,7 +82,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.launcher3", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.launcher3.xml", filename_from_src: true, @@ -90,7 +90,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.provision", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.provision.xml", filename_from_src: true, @@ -98,7 +98,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.settings", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.settings.xml", filename_from_src: true, @@ -114,7 +114,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.storagemanager", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.storagemanager.xml", filename_from_src: true, @@ -122,7 +122,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.systemui", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.systemui.xml", filename_from_src: true, diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk new file mode 100644 index 000000000000..783a7edadeb7 --- /dev/null +++ b/data/etc/CleanSpec.mk @@ -0,0 +1,60 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.carrierconfig.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.carrierconfig.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.emergency.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.emergency.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.provision.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.provision.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.settings.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.settings.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.launcher3.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.launcher3.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.systemui.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.systemui.xml) +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/data/etc/OWNERS b/data/etc/OWNERS index ea66ee373785..70d467829269 100644 --- a/data/etc/OWNERS +++ b/data/etc/OWNERS @@ -1 +1 @@ -per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com, cbrubaker@google.com, jeffv@google.com, moltmann@google.com +per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com, cbrubaker@google.com, jeffv@google.com, moltmann@google.com, lorenzo@google.com diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp index 9272ea5e584b..7faf4cdcf66d 100644 --- a/data/etc/car/Android.bp +++ b/data/etc/car/Android.bp @@ -126,5 +126,5 @@ prebuilt_etc { sub_dir: "permissions", src: "com.android.car.developeroptions.xml", filename_from_src: true, - product_specific: true, + system_ext_specific: true, } diff --git a/data/etc/car/CleanSpec.mk b/data/etc/car/CleanSpec.mk new file mode 100644 index 000000000000..18f7d343676b --- /dev/null +++ b/data/etc/car/CleanSpec.mk @@ -0,0 +1,50 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.car.developeroptions.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.car.developeroptions.xml) +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml index ba877f8d0d02..cc1ce9bbeecb 100644 --- a/data/etc/com.android.settings.xml +++ b/data/etc/com.android.settings.xml @@ -42,8 +42,8 @@ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> <permission name="android.permission.READ_SEARCH_INDEXABLES"/> <permission name="android.permission.REBOOT"/> - <permission name="android.permission.SET_TIME"/> <permission name="android.permission.STATUS_BAR"/> + <permission name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE"/> <permission name="android.permission.TETHER_PRIVILEGED"/> <permission name="android.permission.USE_RESERVED_DISK"/> <permission name="android.permission.USER_ACTIVITY"/> diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index a305d48c4633..1d735674d72d 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -22,7 +22,6 @@ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/> <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/> - <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/> <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/> <permission name="android.permission.CONTROL_VPN"/> @@ -38,6 +37,7 @@ <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> + <permission name="android.permission.OBSERVE_NETWORK_POLICY"/> <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/> <permission name="android.permission.READ_DREAM_STATE"/> <permission name="android.permission.READ_FRAME_BUFFER"/> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index c9097341a18e..eec2072c6d5d 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -67,7 +67,6 @@ applications that come with the platform <privapp-permissions package="com.android.managedprovisioning"> <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <permission name="android.permission.CHANGE_CONFIGURATION"/> - <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.CRYPT_KEEPER"/> <permission name="android.permission.DELETE_PACKAGES"/> <permission name="android.permission.INSTALL_PACKAGES"/> @@ -155,12 +154,12 @@ applications that come with the platform <permission name="android.permission.REGISTER_CALL_PROVIDER"/> <permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/> <permission name="android.permission.SEND_RESPOND_VIA_MESSAGE"/> - <permission name="android.permission.SET_TIME"/> <permission name="android.permission.SET_TIME_ZONE"/> <permission name="android.permission.SHUTDOWN"/> <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/> <permission name="android.permission.STATUS_BAR"/> <permission name="android.permission.STOP_APP_SWITCHES"/> + <permission name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE"/> <permission name="android.permission.UPDATE_APP_OPS_STATS"/> <permission name="android.permission.UPDATE_DEVICE_STATS"/> <permission name="android.permission.UPDATE_LOCK"/> @@ -238,7 +237,9 @@ applications that come with the platform <permission name="android.permission.MANAGE_USB"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> + <permission name="android.permission.TETHER_PRIVILEGED"/> <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + <permission name="android.permission.UPDATE_DEVICE_STATS"/> </privapp-permissions> <privapp-permissions package="com.android.server.telecom"> @@ -360,7 +361,6 @@ applications that come with the platform </privapp-permissions> <privapp-permissions package="com.android.vpndialogs"> - <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.CONTROL_VPN"/> </privapp-permissions> diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index 6e7f286d19a7..bee8d5efc933 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -21,7 +21,7 @@ import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas.VertexMode; import android.graphics.text.MeasuredText; import android.text.GraphicsOperations; diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 44710178da5e..a8b7e1fa0113 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -21,8 +21,8 @@ import android.annotation.ColorInt; import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.ResourcesImpl; import android.hardware.HardwareBuffer; import android.os.Build; diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 5623a8a49b35..bad487b47682 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -20,7 +20,7 @@ import static android.graphics.BitmapFactory.Options.validate; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.content.res.Resources; import android.os.Trace; diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java index 629d8c131b68..34eba97819aa 100644 --- a/graphics/java/android/graphics/BitmapRegionDecoder.java +++ b/graphics/java/android/graphics/BitmapRegionDecoder.java @@ -15,7 +15,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.os.Build; diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 198d1e7bc956..edf53c491311 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -17,7 +17,7 @@ package android.graphics; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Shader used to draw a bitmap as a texture. The bitmap can be repeated or diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java index cbd4eadca30a..80a3740d2f4e 100644 --- a/graphics/java/android/graphics/Camera.java +++ b/graphics/java/android/graphics/Camera.java @@ -16,7 +16,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A camera instance can be used to compute 3D transformations and diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 5648b854db40..d03472856cf4 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -22,7 +22,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.text.MeasuredText; import android.os.Build; diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java index 1275e0827580..4263772c1c2c 100644 --- a/graphics/java/android/graphics/CanvasProperty.java +++ b/graphics/java/android/graphics/CanvasProperty.java @@ -16,7 +16,8 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import com.android.internal.util.VirtualRefBasePtr; /** diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java index 0f7980cc32e4..a8b18a9fcb1f 100644 --- a/graphics/java/android/graphics/ColorMatrixColorFilter.java +++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java @@ -18,7 +18,7 @@ package android.graphics; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A color filter that transforms colors through a 4x5 color matrix. This filter diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index 5af0da85bb39..254892013d51 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -17,7 +17,7 @@ package android.graphics; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.graphics.fonts.FontVariationAxis; import android.text.TextUtils; diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 21cc3757a40e..c146bbd4441b 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -16,7 +16,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.fonts.FontVariationAxis; import android.text.FontConfig; import android.util.Xml; diff --git a/graphics/java/android/graphics/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java index 3b1fc70397ea..99fa5eef7bbd 100644 --- a/graphics/java/android/graphics/GraphicBuffer.java +++ b/graphics/java/android/graphics/GraphicBuffer.java @@ -16,7 +16,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 2d5babc5ebdb..dbdb6971c6c5 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -28,8 +28,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java index 62a890ff4f0b..221dfa192795 100644 --- a/graphics/java/android/graphics/LightingColorFilter.java +++ b/graphics/java/android/graphics/LightingColorFilter.java @@ -22,7 +22,7 @@ package android.graphics; import android.annotation.ColorInt; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A color filter that can be used to simulate simple lighting effects. diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java index 12e63c09d76b..3f3ad967fe97 100644 --- a/graphics/java/android/graphics/LinearGradient.java +++ b/graphics/java/android/graphics/LinearGradient.java @@ -20,7 +20,7 @@ import android.annotation.ColorInt; import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class LinearGradient extends Shader { diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java index 22b6401fdc2e..cf914c2c3eae 100644 --- a/graphics/java/android/graphics/Matrix.java +++ b/graphics/java/android/graphics/Matrix.java @@ -16,7 +16,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java index 6f030ffac2df..4b3924f0d55f 100644 --- a/graphics/java/android/graphics/Movie.java +++ b/graphics/java/android/graphics/Movie.java @@ -16,7 +16,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.os.Build; diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java index c4c1eaceb4fc..ff3239348240 100644 --- a/graphics/java/android/graphics/NinePatch.java +++ b/graphics/java/android/graphics/NinePatch.java @@ -16,7 +16,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The NinePatch class permits drawing a bitmap in nine or more sections. diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java index 1fc056c3652f..91a60c327bf0 100644 --- a/graphics/java/android/graphics/Outline.java +++ b/graphics/java/android/graphics/Outline.java @@ -19,7 +19,7 @@ package android.graphics; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.drawable.Drawable; import java.lang.annotation.Retention; diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index b7316ab03618..dcb669d84272 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -24,7 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; import android.annotation.Size; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.fonts.FontVariationAxis; import android.os.Build; import android.os.LocaleList; diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java index 7282d52d6e23..1362fd864d29 100644 --- a/graphics/java/android/graphics/Path.java +++ b/graphics/java/android/graphics/Path.java @@ -20,7 +20,7 @@ import android.annotation.FloatRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java index 8d12cbffc793..390d3d414346 100644 --- a/graphics/java/android/graphics/Picture.java +++ b/graphics/java/android/graphics/Picture.java @@ -17,7 +17,7 @@ package android.graphics; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.InputStream; import java.io.OutputStream; diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java index bc1f66fdd5c0..1275cb9ca4f9 100644 --- a/graphics/java/android/graphics/PorterDuff.java +++ b/graphics/java/android/graphics/PorterDuff.java @@ -16,7 +16,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * <p>This class contains the list of alpha compositing and blending modes diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index cc2d3a8969fc..50ecb62e7fcc 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -18,7 +18,7 @@ package android.graphics; import android.annotation.ColorInt; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A color filter that can be used to tint the source pixels using a single diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java index acbe3da75247..96b7b9a78ba8 100644 --- a/graphics/java/android/graphics/RadialGradient.java +++ b/graphics/java/android/graphics/RadialGradient.java @@ -20,7 +20,7 @@ import android.annotation.ColorInt; import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class RadialGradient extends Shader { @UnsupportedAppUsage diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java index d47f682ec2d3..270725ab9805 100644 --- a/graphics/java/android/graphics/Rect.java +++ b/graphics/java/android/graphics/Rect.java @@ -19,7 +19,7 @@ package android.graphics; import android.annotation.CheckResult; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java index ec7f7a05b685..d8d96413a93d 100644 --- a/graphics/java/android/graphics/Region.java +++ b/graphics/java/android/graphics/Region.java @@ -17,7 +17,7 @@ package android.graphics; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.Pools.SynchronizedPool; diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index 3050d1dae5e4..5335aa4725ad 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -20,7 +20,7 @@ import android.annotation.ColorInt; import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import libcore.util.NativeAllocationRegistry; diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index 99f440d599cb..697daa8b7b70 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -17,7 +17,7 @@ package android.graphics; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; import android.os.Message; diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java index 667f45afe500..08520048b787 100644 --- a/graphics/java/android/graphics/SweepGradient.java +++ b/graphics/java/android/graphics/SweepGradient.java @@ -20,7 +20,7 @@ import android.annotation.ColorInt; import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class SweepGradient extends Shader { @UnsupportedAppUsage diff --git a/graphics/java/android/graphics/TableMaskFilter.java b/graphics/java/android/graphics/TableMaskFilter.java index d81c491e07e0..204f9705852a 100644 --- a/graphics/java/android/graphics/TableMaskFilter.java +++ b/graphics/java/android/graphics/TableMaskFilter.java @@ -16,7 +16,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/graphics/java/android/graphics/TemporaryBuffer.java b/graphics/java/android/graphics/TemporaryBuffer.java index 0ae2c703c21c..ef3f7f704e0d 100644 --- a/graphics/java/android/graphics/TemporaryBuffer.java +++ b/graphics/java/android/graphics/TemporaryBuffer.java @@ -16,7 +16,8 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import com.android.internal.util.ArrayUtils; /** diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 6d20ec32cdc4..a2dd9a8322b6 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -25,7 +25,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.graphics.fonts.Font; import android.graphics.fonts.FontFamily; diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java index 6f4adfde7ff9..e79fb76d806e 100644 --- a/graphics/java/android/graphics/Xfermode.java +++ b/graphics/java/android/graphics/Xfermode.java @@ -21,7 +21,7 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Xfermode is the base class for objects that are called to implement custom diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java index 82f587086428..d8946009483c 100644 --- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java @@ -19,7 +19,7 @@ package android.graphics.drawable; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; import android.content.res.Resources.Theme; diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java index b29fd4db5803..686f146e9c18 100644 --- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java @@ -18,23 +18,23 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; -import android.graphics.Canvas; -import android.graphics.Rect; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; -import android.content.res.TypedArray; import android.content.res.Resources.Theme; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.os.SystemClock; import android.util.AttributeSet; import android.util.TypedValue; -import android.os.SystemClock; + +import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; -import com.android.internal.R; - /** * @hide */ diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java index 11a46c4ba9b9..06159d8a0558 100644 --- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java @@ -20,7 +20,7 @@ import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 66947da9166f..1acf6c512fbd 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -25,9 +25,9 @@ import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.Application; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index 57764c2cb693..8c3fa441cbb0 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -16,21 +16,21 @@ package android.graphics.drawable; -import com.android.internal.R; - -import java.io.IOException; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; -import android.content.res.TypedArray; import android.content.res.Resources.Theme; +import android.content.res.TypedArray; import android.os.SystemClock; import android.util.AttributeSet; +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + /** * An object used to create frame-by-frame animations, defined by a series of * Drawable objects, which can be used as a View object's background. diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index e4aa774fd434..4e768c9eddfb 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -17,7 +17,7 @@ package android.graphics.drawable; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index 31fdb025bbc5..69ed9b423d48 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -16,20 +16,22 @@ package android.graphics.drawable; -import com.android.internal.R; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; -import android.content.res.TypedArray; import android.content.res.Resources.Theme; -import android.graphics.*; -import android.view.Gravity; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.Rect; import android.util.AttributeSet; +import android.view.Gravity; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index f5fa8c546bed..e93e7dfbe22c 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -20,7 +20,7 @@ import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 08409869c626..e70529b6cd1a 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -22,7 +22,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 090d915a2f67..51b299c9ee5e 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -17,7 +17,7 @@ package android.graphics.drawable; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java index bad3791a9c24..3408b64e7536 100644 --- a/graphics/java/android/graphics/drawable/DrawableInflater.java +++ b/graphics/java/android/graphics/drawable/DrawableInflater.java @@ -16,19 +16,19 @@ package android.graphics.drawable; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.util.AttributeSet; import android.view.InflateException; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.lang.reflect.Constructor; import java.util.HashMap; diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java index 64fc7042dfc7..e8cb42e75ea2 100644 --- a/graphics/java/android/graphics/drawable/DrawableWrapper.java +++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index b9945cc735d8..b50ec0d5e3fd 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -22,7 +22,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index 3658f89abae1..63662099c4c8 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -21,7 +21,7 @@ import android.annotation.DrawableRes; import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index bc8a4cbd7e9d..005a4d175fd5 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 760d554888ee..fb4146f04bc9 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 8561d95ddd88..99d27ba4c469 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 1540cc22e295..e5e4d4527fca 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index db5f082bd853..43766b636adb 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -16,22 +16,22 @@ package android.graphics.drawable; -import com.android.internal.R; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; -import android.graphics.Canvas; -import android.graphics.Rect; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; -import android.content.res.TypedArray; import android.content.res.Resources.Theme; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.util.AttributeSet; import android.util.MathUtils; import android.util.TypedValue; -import android.util.AttributeSet; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index 91ed061e511d..af7eed4b3897 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -16,14 +16,9 @@ package android.graphics.drawable; -import com.android.internal.R; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; @@ -34,6 +29,11 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; /** diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index f67188c22609..2920acbe514c 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java index 276f3662189b..401e05ffc139 100644 --- a/graphics/java/android/graphics/drawable/TransitionDrawable.java +++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java @@ -16,7 +16,7 @@ package android.graphics.drawable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.Resources; import android.graphics.Canvas; diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index aa19b2a0e94c..e6fa866df3ab 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -16,7 +16,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.ComplexColor; diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java index bcee559d8291..4e6580ea5f53 100644 --- a/graphics/java/android/graphics/fonts/FontVariationAxis.java +++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java @@ -18,7 +18,7 @@ package android.graphics.fonts; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.text.TextUtils; diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java index bd1a49205fd5..54710e58687c 100644 --- a/graphics/java/android/graphics/pdf/PdfRenderer.java +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -19,7 +19,7 @@ package android.graphics.pdf; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Matrix; @@ -29,7 +29,9 @@ import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; + import com.android.internal.util.Preconditions; + import dalvik.system.CloseGuard; import libcore.io.IoUtils; diff --git a/identity/MODULE_LICENSE_APACHE2 b/identity/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/identity/MODULE_LICENSE_APACHE2 diff --git a/identity/NOTICE b/identity/NOTICE new file mode 100644 index 000000000000..64aaa8dbd68e --- /dev/null +++ b/identity/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2009, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/identity/OWNERS b/identity/OWNERS new file mode 100644 index 000000000000..533d90b2cd13 --- /dev/null +++ b/identity/OWNERS @@ -0,0 +1,3 @@ +swillden@google.com +zeuthen@google.com + diff --git a/identity/java/android/security/identity/AccessControlProfile.java b/identity/java/android/security/identity/AccessControlProfile.java new file mode 100644 index 000000000000..10e451c97707 --- /dev/null +++ b/identity/java/android/security/identity/AccessControlProfile.java @@ -0,0 +1,131 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +import java.security.cert.X509Certificate; + +/** + * A class used to specify access controls. + */ +public class AccessControlProfile { + private AccessControlProfileId mAccessControlProfileId = new AccessControlProfileId(0); + private X509Certificate mReaderCertificate = null; + private boolean mUserAuthenticationRequired = true; + private long mUserAuthenticationTimeout = 0; + + private AccessControlProfile() { + } + + AccessControlProfileId getAccessControlProfileId() { + return mAccessControlProfileId; + } + + long getUserAuthenticationTimeout() { + return mUserAuthenticationTimeout; + } + + boolean isUserAuthenticationRequired() { + return mUserAuthenticationRequired; + } + + X509Certificate getReaderCertificate() { + return mReaderCertificate; + } + + /** + * A builder for {@link AccessControlProfile}. + */ + public static final class Builder { + private AccessControlProfile mProfile; + + /** + * Each access control profile has numeric identifier that must be unique within the + * context of a Credential and may be used to reference the profile. + * + * <p>By default, the resulting {@link AccessControlProfile} will require user + * authentication with a timeout of zero, thus requiring the holder to authenticate for + * every presentation where data elements using this access control profile is used.</p> + * + * @param accessControlProfileId the access control profile identifier. + */ + public Builder(@NonNull AccessControlProfileId accessControlProfileId) { + mProfile = new AccessControlProfile(); + mProfile.mAccessControlProfileId = accessControlProfileId; + } + + /** + * Set whether user authentication is required. + * + * <p>This should be used sparingly since disabling user authentication on just a single + * data element can easily create a + * <a href="https://en.wikipedia.org/wiki/Relay_attack">Relay Attack</a> if the device + * on which the credential is stored is compromised.</p> + * + * @param userAuthenticationRequired Set to true if user authentication is required, + * false otherwise. + * @return The builder. + */ + public @NonNull Builder setUserAuthenticationRequired(boolean userAuthenticationRequired) { + mProfile.mUserAuthenticationRequired = userAuthenticationRequired; + return this; + } + + /** + * Sets the authentication timeout to use. + * + * <p>The authentication timeout specifies the amount of time, in milliseconds, for which a + * user authentication is valid, if user authentication is required (see + * {@link #setUserAuthenticationRequired(boolean)}).</p> + * + * <p>If the timeout is zero, then authentication is always required for each reader + * session.</p> + * + * @param userAuthenticationTimeoutMillis the authentication timeout, in milliseconds. + * @return The builder. + */ + public @NonNull Builder setUserAuthenticationTimeout(long userAuthenticationTimeoutMillis) { + mProfile.mUserAuthenticationTimeout = userAuthenticationTimeoutMillis; + return this; + } + + /** + * Sets the reader certificate to use when checking access control. + * + * <p>If set, this is checked against the certificate chain presented by + * reader. The access check is fulfilled only if one of the certificates + * in the chain, matches the certificate set by this method.</p> + * + * @param readerCertificate the certificate to use for the access control check. + * @return The builder. + */ + public @NonNull Builder setReaderCertificate(@NonNull X509Certificate readerCertificate) { + mProfile.mReaderCertificate = readerCertificate; + return this; + } + + /** + * Creates a new {@link AccessControlProfile} from the data supplied to the builder. + * + * @return The created {@link AccessControlProfile} object. + */ + public @NonNull AccessControlProfile build() { + return mProfile; + } + } +} diff --git a/identity/java/android/security/identity/AccessControlProfileId.java b/identity/java/android/security/identity/AccessControlProfileId.java new file mode 100644 index 000000000000..3d5945065ad7 --- /dev/null +++ b/identity/java/android/security/identity/AccessControlProfileId.java @@ -0,0 +1,42 @@ +/* + * Copyright 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.security.identity; + +/** + * A class used to wrap an access control profile identifiers. + */ +public class AccessControlProfileId { + private int mId = 0; + + /** + * Constructs a new object holding a numerical identifier. + * + * @param id the identifier. + */ + public AccessControlProfileId(int id) { + this.mId = id; + } + + /** + * Gets the numerical identifier wrapped by this object. + * + * @return the identifier. + */ + public int getId() { + return this.mId; + } +} diff --git a/identity/java/android/security/identity/AlreadyPersonalizedException.java b/identity/java/android/security/identity/AlreadyPersonalizedException.java new file mode 100644 index 000000000000..1933882aa4bf --- /dev/null +++ b/identity/java/android/security/identity/AlreadyPersonalizedException.java @@ -0,0 +1,43 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if trying to create a credential which already exists. + */ +public class AlreadyPersonalizedException extends IdentityCredentialException { + /** + * Constructs a new {@link AlreadyPersonalizedException} exception. + * + * @param message the detail message. + */ + public AlreadyPersonalizedException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link AlreadyPersonalizedException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public AlreadyPersonalizedException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/CipherSuiteNotSupportedException.java b/identity/java/android/security/identity/CipherSuiteNotSupportedException.java new file mode 100644 index 000000000000..e7a6c8969482 --- /dev/null +++ b/identity/java/android/security/identity/CipherSuiteNotSupportedException.java @@ -0,0 +1,43 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if trying to use a cipher suite which isn't supported. + */ +public class CipherSuiteNotSupportedException extends IdentityCredentialException { + /** + * Constructs a new {@link CipherSuiteNotSupportedException} exception. + * + * @param message the detail message. + */ + public CipherSuiteNotSupportedException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link CipherSuiteNotSupportedException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public CipherSuiteNotSupportedException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java new file mode 100644 index 000000000000..c520331ab72d --- /dev/null +++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java @@ -0,0 +1,424 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.LinkedList; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyAgreement; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +class CredstoreIdentityCredential extends IdentityCredential { + + private static final String TAG = "CredstoreIdentityCredential"; + private String mCredentialName; + private @IdentityCredentialStore.Ciphersuite int mCipherSuite; + private Context mContext; + private ICredential mBinder; + + CredstoreIdentityCredential(Context context, String credentialName, + @IdentityCredentialStore.Ciphersuite int cipherSuite, + ICredential binder) { + mContext = context; + mCredentialName = credentialName; + mCipherSuite = cipherSuite; + mBinder = binder; + } + + private KeyPair mEphemeralKeyPair = null; + private SecretKey mSecretKey = null; + private SecretKey mReaderSecretKey = null; + private int mEphemeralCounter; + private int mReadersExpectedEphemeralCounter; + + private void ensureEphemeralKeyPair() { + if (mEphemeralKeyPair != null) { + return; + } + try { + // This PKCS#12 blob is generated in credstore, using BoringSSL. + // + // The main reason for this convoluted approach and not just sending the decomposed + // key-pair is that this would require directly using (device-side) BouncyCastle which + // is tricky due to various API hiding efforts. So instead we have credstore generate + // this PKCS#12 blob. The blob is encrypted with no password (sadly, also, BoringSSL + // doesn't support not using encryption when building a PKCS#12 blob). + // + byte[] pkcs12 = mBinder.createEphemeralKeyPair(); + String alias = "ephemeralKey"; + char[] password = {}; + + KeyStore ks = KeyStore.getInstance("PKCS12"); + ByteArrayInputStream bais = new ByteArrayInputStream(pkcs12); + ks.load(bais, password); + PrivateKey privKey = (PrivateKey) ks.getKey(alias, password); + + Certificate cert = ks.getCertificate(alias); + PublicKey pubKey = cert.getPublicKey(); + + mEphemeralKeyPair = new KeyPair(pubKey, privKey); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } catch (KeyStoreException + | CertificateException + | UnrecoverableKeyException + | NoSuchAlgorithmException + | IOException e) { + throw new RuntimeException("Unexpected exception ", e); + } + } + + @Override + public @NonNull KeyPair createEphemeralKeyPair() { + ensureEphemeralKeyPair(); + return mEphemeralKeyPair; + } + + @Override + public void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey) + throws InvalidKeyException { + try { + byte[] uncompressedForm = + Util.publicKeyEncodeUncompressedForm(readerEphemeralPublicKey); + mBinder.setReaderEphemeralPublicKey(uncompressedForm); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + + ensureEphemeralKeyPair(); + + try { + KeyAgreement ka = KeyAgreement.getInstance("ECDH"); + ka.init(mEphemeralKeyPair.getPrivate()); + ka.doPhase(readerEphemeralPublicKey, true); + byte[] sharedSecret = ka.generateSecret(); + + byte[] salt = new byte[1]; + byte[] info = new byte[0]; + + salt[0] = 0x01; + byte[] derivedKey = Util.computeHkdf("HmacSha256", sharedSecret, salt, info, 32); + mSecretKey = new SecretKeySpec(derivedKey, "AES"); + + salt[0] = 0x00; + derivedKey = Util.computeHkdf("HmacSha256", sharedSecret, salt, info, 32); + mReaderSecretKey = new SecretKeySpec(derivedKey, "AES"); + + mEphemeralCounter = 0; + mReadersExpectedEphemeralCounter = 0; + + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Error performing key agreement", e); + } + } + + @Override + public @NonNull byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext) { + byte[] messageCiphertextAndAuthTag = null; + try { + ByteBuffer iv = ByteBuffer.allocate(12); + iv.putInt(0, 0x00000000); + iv.putInt(4, 0x00000001); + iv.putInt(8, mEphemeralCounter); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + GCMParameterSpec encryptionParameterSpec = new GCMParameterSpec(128, iv.array()); + cipher.init(Cipher.ENCRYPT_MODE, mSecretKey, encryptionParameterSpec); + messageCiphertextAndAuthTag = cipher.doFinal(messagePlaintext); + } catch (BadPaddingException + | IllegalBlockSizeException + | NoSuchPaddingException + | InvalidKeyException + | NoSuchAlgorithmException + | InvalidAlgorithmParameterException e) { + throw new RuntimeException("Error encrypting message", e); + } + mEphemeralCounter += 1; + return messageCiphertextAndAuthTag; + } + + @Override + public @NonNull byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext) + throws MessageDecryptionException { + ByteBuffer iv = ByteBuffer.allocate(12); + iv.putInt(0, 0x00000000); + iv.putInt(4, 0x00000000); + iv.putInt(8, mReadersExpectedEphemeralCounter); + byte[] plainText = null; + try { + final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, mReaderSecretKey, + new GCMParameterSpec(128, iv.array())); + plainText = cipher.doFinal(messageCiphertext); + } catch (BadPaddingException + | IllegalBlockSizeException + | InvalidAlgorithmParameterException + | InvalidKeyException + | NoSuchAlgorithmException + | NoSuchPaddingException e) { + throw new MessageDecryptionException("Error decrypting message", e); + } + mReadersExpectedEphemeralCounter += 1; + return plainText; + } + + @Override + public @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain() { + try { + byte[] certsBlob = mBinder.getCredentialKeyCertificateChain(); + ByteArrayInputStream bais = new ByteArrayInputStream(certsBlob); + + Collection<? extends Certificate> certs = null; + try { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + certs = factory.generateCertificates(bais); + } catch (CertificateException e) { + throw new RuntimeException("Error decoding certificates", e); + } + + LinkedList<X509Certificate> x509Certs = new LinkedList<>(); + for (Certificate cert : certs) { + x509Certs.add((X509Certificate) cert); + } + return x509Certs; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + private boolean mAllowUsingExhaustedKeys = true; + + @Override + public void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys) { + mAllowUsingExhaustedKeys = allowUsingExhaustedKeys; + } + + private boolean mOperationHandleSet = false; + private long mOperationHandle = 0; + + /** + * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an + * operation handle. + * + * @hide + */ + @Override + public long getCredstoreOperationHandle() { + if (!mOperationHandleSet) { + try { + mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys); + mOperationHandleSet = true; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_NO_AUTHENTICATION_KEY_AVAILABLE) { + // The NoAuthenticationKeyAvailableException will be thrown when + // the caller proceeds to call getEntries(). + } + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + return mOperationHandle; + } + + @NonNull + @Override + public ResultData getEntries( + @Nullable byte[] requestMessage, + @NonNull Map<String, Collection<String>> entriesToRequest, + @Nullable byte[] sessionTranscript, + @Nullable byte[] readerSignature) + throws SessionTranscriptMismatchException, NoAuthenticationKeyAvailableException, + InvalidReaderSignatureException, EphemeralPublicKeyNotFoundException, + InvalidRequestMessageException { + + RequestNamespaceParcel[] rnsParcels = new RequestNamespaceParcel[entriesToRequest.size()]; + int n = 0; + for (String namespaceName : entriesToRequest.keySet()) { + Collection<String> entryNames = entriesToRequest.get(namespaceName); + rnsParcels[n] = new RequestNamespaceParcel(); + rnsParcels[n].namespaceName = namespaceName; + rnsParcels[n].entries = new RequestEntryParcel[entryNames.size()]; + int m = 0; + for (String entryName : entryNames) { + rnsParcels[n].entries[m] = new RequestEntryParcel(); + rnsParcels[n].entries[m].name = entryName; + m++; + } + n++; + } + + GetEntriesResultParcel resultParcel = null; + try { + resultParcel = mBinder.getEntries( + requestMessage != null ? requestMessage : new byte[0], + rnsParcels, + sessionTranscript != null ? sessionTranscript : new byte[0], + readerSignature != null ? readerSignature : new byte[0], + mAllowUsingExhaustedKeys); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) { + throw new EphemeralPublicKeyNotFoundException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_INVALID_READER_SIGNATURE) { + throw new InvalidReaderSignatureException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_NO_AUTHENTICATION_KEY_AVAILABLE) { + throw new NoAuthenticationKeyAvailableException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_INVALID_ITEMS_REQUEST_MESSAGE) { + throw new InvalidRequestMessageException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_SESSION_TRANSCRIPT_MISMATCH) { + throw new SessionTranscriptMismatchException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + byte[] mac = resultParcel.mac; + if (mac != null && mac.length == 0) { + mac = null; + } + CredstoreResultData.Builder resultDataBuilder = new CredstoreResultData.Builder( + resultParcel.staticAuthenticationData, resultParcel.deviceNameSpaces, mac); + + for (ResultNamespaceParcel resultNamespaceParcel : resultParcel.resultNamespaces) { + for (ResultEntryParcel resultEntryParcel : resultNamespaceParcel.entries) { + if (resultEntryParcel.status == ICredential.STATUS_OK) { + resultDataBuilder.addEntry(resultNamespaceParcel.namespaceName, + resultEntryParcel.name, resultEntryParcel.value); + } else { + resultDataBuilder.addErrorStatus(resultNamespaceParcel.namespaceName, + resultEntryParcel.name, + resultEntryParcel.status); + } + } + } + return resultDataBuilder.build(); + } + + @Override + public void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) { + try { + mBinder.setAvailableAuthenticationKeys(keyCount, maxUsesPerKey); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @Override + public @NonNull Collection<X509Certificate> getAuthKeysNeedingCertification() { + try { + AuthKeyParcel[] authKeyParcels = mBinder.getAuthKeysNeedingCertification(); + LinkedList<X509Certificate> x509Certs = new LinkedList<>(); + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + for (AuthKeyParcel authKeyParcel : authKeyParcels) { + Collection<? extends Certificate> certs = null; + ByteArrayInputStream bais = new ByteArrayInputStream(authKeyParcel.x509cert); + certs = factory.generateCertificates(bais); + if (certs.size() != 1) { + throw new RuntimeException("Returned blob yields more than one X509 cert"); + } + X509Certificate authKeyCert = (X509Certificate) certs.iterator().next(); + x509Certs.add(authKeyCert); + } + return x509Certs; + } catch (CertificateException e) { + throw new RuntimeException("Error decoding authenticationKey", e); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @Override + public void storeStaticAuthenticationData(X509Certificate authenticationKey, + byte[] staticAuthData) + throws UnknownAuthenticationKeyException { + try { + AuthKeyParcel authKeyParcel = new AuthKeyParcel(); + authKeyParcel.x509cert = authenticationKey.getEncoded(); + mBinder.storeStaticAuthenticationData(authKeyParcel, staticAuthData); + } catch (CertificateEncodingException e) { + throw new RuntimeException("Error encoding authenticationKey", e); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_AUTHENTICATION_KEY_NOT_FOUND) { + throw new UnknownAuthenticationKeyException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + } + + @Override + public @NonNull int[] getAuthenticationDataUsageCount() { + try { + int[] usageCount = mBinder.getAuthenticationDataUsageCount(); + return usageCount; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } +} diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java new file mode 100644 index 000000000000..dcc6b95aec02 --- /dev/null +++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java @@ -0,0 +1,162 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.ServiceManager; + +class CredstoreIdentityCredentialStore extends IdentityCredentialStore { + + private static final String TAG = "CredstoreIdentityCredentialStore"; + + private Context mContext = null; + private ICredentialStore mStore = null; + + private CredstoreIdentityCredentialStore(@NonNull Context context, ICredentialStore store) { + mContext = context; + mStore = store; + } + + static CredstoreIdentityCredentialStore getInstanceForType(@NonNull Context context, + int credentialStoreType) { + ICredentialStoreFactory storeFactory = + ICredentialStoreFactory.Stub.asInterface( + ServiceManager.getService("android.security.identity")); + + ICredentialStore credStore = null; + try { + credStore = storeFactory.getCredentialStore(credentialStoreType); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_GENERIC) { + return null; + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + if (credStore == null) { + return null; + } + + return new CredstoreIdentityCredentialStore(context, credStore); + } + + private static CredstoreIdentityCredentialStore sInstanceDefault = null; + private static CredstoreIdentityCredentialStore sInstanceDirectAccess = null; + + public static @Nullable IdentityCredentialStore getInstance(@NonNull Context context) { + if (sInstanceDefault == null) { + sInstanceDefault = getInstanceForType(context, + ICredentialStoreFactory.CREDENTIAL_STORE_TYPE_DEFAULT); + } + return sInstanceDefault; + } + + public static @Nullable IdentityCredentialStore getDirectAccessInstance(@NonNull + Context context) { + if (sInstanceDirectAccess == null) { + sInstanceDirectAccess = getInstanceForType(context, + ICredentialStoreFactory.CREDENTIAL_STORE_TYPE_DIRECT_ACCESS); + } + return sInstanceDirectAccess; + } + + @Override + public @NonNull String[] getSupportedDocTypes() { + try { + SecurityHardwareInfoParcel info; + info = mStore.getSecurityHardwareInfo(); + return info.supportedDocTypes; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @Override public @NonNull WritableIdentityCredential createCredential( + @NonNull String credentialName, + @NonNull String docType) throws AlreadyPersonalizedException, + DocTypeNotSupportedException { + try { + IWritableCredential wc; + wc = mStore.createCredential(credentialName, docType); + return new CredstoreWritableIdentityCredential(mContext, credentialName, docType, wc); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_ALREADY_PERSONALIZED) { + throw new AlreadyPersonalizedException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_DOCUMENT_TYPE_NOT_SUPPORTED) { + throw new DocTypeNotSupportedException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + } + + @Override public @Nullable IdentityCredential getCredentialByName( + @NonNull String credentialName, + @Ciphersuite int cipherSuite) throws CipherSuiteNotSupportedException { + try { + ICredential credstoreCredential; + credstoreCredential = mStore.getCredentialByName(credentialName, cipherSuite); + return new CredstoreIdentityCredential(mContext, credentialName, cipherSuite, + credstoreCredential); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_NO_SUCH_CREDENTIAL) { + return null; + } else if (e.errorCode == ICredentialStore.ERROR_CIPHER_SUITE_NOT_SUPPORTED) { + throw new CipherSuiteNotSupportedException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + } + + @Override + public @Nullable byte[] deleteCredentialByName(@NonNull String credentialName) { + ICredential credstoreCredential = null; + try { + try { + credstoreCredential = mStore.getCredentialByName(credentialName, + CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_NO_SUCH_CREDENTIAL) { + return null; + } + } + byte[] proofOfDeletion = credstoreCredential.deleteCredential(); + return proofOfDeletion; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + +} diff --git a/identity/java/android/security/identity/CredstoreResultData.java b/identity/java/android/security/identity/CredstoreResultData.java new file mode 100644 index 000000000000..ef7afca6b888 --- /dev/null +++ b/identity/java/android/security/identity/CredstoreResultData.java @@ -0,0 +1,162 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; + +/** + * An object that contains the result of retrieving data from a credential. This is used to return + * data requested from a {@link IdentityCredential}. + */ +class CredstoreResultData extends ResultData { + + byte[] mStaticAuthenticationData = null; + byte[] mAuthenticatedData = null; + byte[] mMessageAuthenticationCode = null; + + private Map<String, Map<String, EntryData>> mData = new LinkedHashMap<>(); + + private static class EntryData { + @Status + int mStatus; + byte[] mValue; + + EntryData(byte[] value, @Status int status) { + this.mValue = value; + this.mStatus = status; + } + } + + CredstoreResultData() {} + + @Override + public @NonNull byte[] getAuthenticatedData() { + return mAuthenticatedData; + } + + @Override + public @Nullable byte[] getMessageAuthenticationCode() { + return mMessageAuthenticationCode; + } + + @Override + public @NonNull byte[] getStaticAuthenticationData() { + return mStaticAuthenticationData; + } + + @Override + public @NonNull Collection<String> getNamespaceNames() { + return Collections.unmodifiableCollection(mData.keySet()); + } + + @Override + public @Nullable Collection<String> getEntryNames(@NonNull String namespaceName) { + Map<String, EntryData> innerMap = mData.get(namespaceName); + if (innerMap == null) { + return null; + } + return Collections.unmodifiableCollection(innerMap.keySet()); + } + + @Override + public @Nullable Collection<String> getRetrievedEntryNames(@NonNull String namespaceName) { + Map<String, EntryData> innerMap = mData.get(namespaceName); + if (innerMap == null) { + return null; + } + LinkedList<String> result = new LinkedList<String>(); + for (Map.Entry<String, EntryData> entry : innerMap.entrySet()) { + if (entry.getValue().mStatus == STATUS_OK) { + result.add(entry.getKey()); + } + } + return result; + } + + private EntryData getEntryData(@NonNull String namespaceName, @NonNull String name) { + Map<String, EntryData> innerMap = mData.get(namespaceName); + if (innerMap == null) { + return null; + } + return innerMap.get(name); + } + + @Override + @Status + public int getStatus(@NonNull String namespaceName, @NonNull String name) { + EntryData value = getEntryData(namespaceName, name); + if (value == null) { + return STATUS_NOT_REQUESTED; + } + return value.mStatus; + } + + @Override + public @Nullable byte[] getEntry(@NonNull String namespaceName, @NonNull String name) { + EntryData value = getEntryData(namespaceName, name); + if (value == null) { + return null; + } + return value.mValue; + } + + static class Builder { + private CredstoreResultData mResultData; + + Builder(byte[] staticAuthenticationData, + byte[] authenticatedData, + byte[] messageAuthenticationCode) { + this.mResultData = new CredstoreResultData(); + this.mResultData.mStaticAuthenticationData = staticAuthenticationData; + this.mResultData.mAuthenticatedData = authenticatedData; + this.mResultData.mMessageAuthenticationCode = messageAuthenticationCode; + } + + private Map<String, EntryData> getOrCreateInnerMap(String namespaceName) { + Map<String, EntryData> innerMap = mResultData.mData.get(namespaceName); + if (innerMap == null) { + innerMap = new LinkedHashMap<>(); + mResultData.mData.put(namespaceName, innerMap); + } + return innerMap; + } + + Builder addEntry(String namespaceName, String name, byte[] value) { + Map<String, EntryData> innerMap = getOrCreateInnerMap(namespaceName); + innerMap.put(name, new EntryData(value, STATUS_OK)); + return this; + } + + Builder addErrorStatus(String namespaceName, String name, @Status int status) { + Map<String, EntryData> innerMap = getOrCreateInnerMap(namespaceName); + innerMap.put(name, new EntryData(null, status)); + return this; + } + + CredstoreResultData build() { + return mResultData; + } + } + +} diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java new file mode 100644 index 000000000000..335636cb07ae --- /dev/null +++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java @@ -0,0 +1,168 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; +import android.content.Context; +import android.security.GateKeeper; + +import java.io.ByteArrayInputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.LinkedList; + +class CredstoreWritableIdentityCredential extends WritableIdentityCredential { + + private static final String TAG = "CredstoreWritableIdentityCredential"; + + private String mDocType; + private String mCredentialName; + private Context mContext; + private IWritableCredential mBinder; + + CredstoreWritableIdentityCredential(Context context, + @NonNull String credentialName, + @NonNull String docType, + IWritableCredential binder) { + mContext = context; + mDocType = docType; + mCredentialName = credentialName; + mBinder = binder; + } + + @NonNull @Override + public Collection<X509Certificate> getCredentialKeyCertificateChain(@NonNull byte[] challenge) { + try { + byte[] certsBlob = mBinder.getCredentialKeyCertificateChain(challenge); + ByteArrayInputStream bais = new ByteArrayInputStream(certsBlob); + + Collection<? extends Certificate> certs = null; + try { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + certs = factory.generateCertificates(bais); + } catch (CertificateException e) { + throw new RuntimeException("Error decoding certificates", e); + } + + LinkedList<X509Certificate> x509Certs = new LinkedList<>(); + for (Certificate cert : certs) { + x509Certs.add((X509Certificate) cert); + } + return x509Certs; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @NonNull @Override + public byte[] personalize(@NonNull PersonalizationData personalizationData) { + + Collection<AccessControlProfile> accessControlProfiles = + personalizationData.getAccessControlProfiles(); + + AccessControlProfileParcel[] acpParcels = + new AccessControlProfileParcel[accessControlProfiles.size()]; + boolean usingUserAuthentication = false; + int n = 0; + for (AccessControlProfile profile : accessControlProfiles) { + acpParcels[n] = new AccessControlProfileParcel(); + acpParcels[n].id = profile.getAccessControlProfileId().getId(); + X509Certificate cert = profile.getReaderCertificate(); + if (cert != null) { + try { + acpParcels[n].readerCertificate = cert.getEncoded(); + } catch (CertificateException e) { + throw new RuntimeException("Error encoding reader certificate", e); + } + } else { + acpParcels[n].readerCertificate = new byte[0]; + } + acpParcels[n].userAuthenticationRequired = profile.isUserAuthenticationRequired(); + acpParcels[n].userAuthenticationTimeoutMillis = profile.getUserAuthenticationTimeout(); + if (profile.isUserAuthenticationRequired()) { + usingUserAuthentication = true; + } + n++; + } + + Collection<String> namespaceNames = personalizationData.getNamespaceNames(); + + EntryNamespaceParcel[] ensParcels = new EntryNamespaceParcel[namespaceNames.size()]; + n = 0; + for (String namespaceName : namespaceNames) { + PersonalizationData.NamespaceData nsd = + personalizationData.getNamespaceData(namespaceName); + + ensParcels[n] = new EntryNamespaceParcel(); + ensParcels[n].namespaceName = namespaceName; + + Collection<String> entryNames = nsd.getEntryNames(); + EntryParcel[] eParcels = new EntryParcel[entryNames.size()]; + int m = 0; + for (String entryName : entryNames) { + eParcels[m] = new EntryParcel(); + eParcels[m].name = entryName; + eParcels[m].value = nsd.getEntryValue(entryName); + Collection<AccessControlProfileId> acpIds = + nsd.getAccessControlProfileIds(entryName); + eParcels[m].accessControlProfileIds = new int[acpIds.size()]; + int o = 0; + for (AccessControlProfileId acpId : acpIds) { + eParcels[m].accessControlProfileIds[o++] = acpId.getId(); + } + m++; + } + ensParcels[n].entries = eParcels; + n++; + } + + // Note: The value 0 is used to convey that no user-authentication is needed for this + // credential. This is to allow creating credentials w/o user authentication on devices + // where Secure lock screen is not enabled. + long secureUserId = 0; + if (usingUserAuthentication) { + secureUserId = getRootSid(); + } + try { + byte[] personalizationReceipt = mBinder.personalize(acpParcels, ensParcels, + secureUserId); + return personalizationReceipt; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + private static long getRootSid() { + long rootSid = GateKeeper.getSecureUserId(); + if (rootSid == 0) { + throw new IllegalStateException("Secure lock screen must be enabled" + + " to create credentials requiring user authentication"); + } + return rootSid; + } + + +} diff --git a/identity/java/android/security/identity/DocTypeNotSupportedException.java b/identity/java/android/security/identity/DocTypeNotSupportedException.java new file mode 100644 index 000000000000..754e44af5411 --- /dev/null +++ b/identity/java/android/security/identity/DocTypeNotSupportedException.java @@ -0,0 +1,43 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if trying to create a credential with an unsupported document type. + */ +public class DocTypeNotSupportedException extends IdentityCredentialException { + /** + * Constructs a new {@link DocTypeNotSupportedException} exception. + * + * @param message the detail message. + */ + public DocTypeNotSupportedException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link DocTypeNotSupportedException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public DocTypeNotSupportedException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java b/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java new file mode 100644 index 000000000000..265f271b54f7 --- /dev/null +++ b/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java @@ -0,0 +1,44 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if the ephemeral public key was not found in the session transcript + * passed to {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])}. + */ +public class EphemeralPublicKeyNotFoundException extends IdentityCredentialException { + /** + * Constructs a new {@link EphemeralPublicKeyNotFoundException} exception. + * + * @param message the detail message. + */ + public EphemeralPublicKeyNotFoundException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link EphemeralPublicKeyNotFoundException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public EphemeralPublicKeyNotFoundException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java new file mode 100644 index 000000000000..bd439199f914 --- /dev/null +++ b/identity/java/android/security/identity/IdentityCredential.java @@ -0,0 +1,309 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Map; + +/** + * Class used to read data from a previously provisioned credential. + * + * Use {@link IdentityCredentialStore#getCredentialByName(String, int)} to get a + * {@link IdentityCredential} instance. + */ +public abstract class IdentityCredential { + /** + * @hide + */ + protected IdentityCredential() {} + + /** + * Create an ephemeral key pair to use to establish a secure channel with a reader. + * + * <p>Most applications will use only the public key, and only to send it to the reader, + * allowing the private key to be used internally for {@link #encryptMessageToReader(byte[])} + * and {@link #decryptMessageFromReader(byte[])}. The private key is also provided for + * applications that wish to use a cipher suite that is not supported by + * {@link IdentityCredentialStore}. + * + * @return ephemeral key pair to use to establish a secure channel with a reader. + */ + public @NonNull abstract KeyPair createEphemeralKeyPair(); + + /** + * Set the ephemeral public key provided by the reader. This must be called before + * {@link #encryptMessageToReader} or {@link #decryptMessageFromReader} can be called. + * + * @param readerEphemeralPublicKey The ephemeral public key provided by the reader to + * establish a secure session. + * @throws InvalidKeyException if the given key is invalid. + */ + public abstract void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey) + throws InvalidKeyException; + + /** + * Encrypt a message for transmission to the reader. + * + * @param messagePlaintext unencrypted message to encrypt. + * @return encrypted message. + */ + public @NonNull abstract byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext); + + /** + * Decrypt a message received from the reader. + * + * @param messageCiphertext encrypted message to decrypt. + * @return decrypted message. + * @throws MessageDecryptionException if the ciphertext couldn't be decrypted. + */ + public @NonNull abstract byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext) + throws MessageDecryptionException; + + /** + * Gets the X.509 certificate chain for the CredentialKey which identifies this + * credential to the issuing authority. This is the same certificate chain that + * was returned by {@link WritableIdentityCredential#getCredentialKeyCertificateChain(byte[])} + * when the credential was first created and its Android Keystore extension will + * contain the <code>challenge</code> data set at that time. See the documentation + * for that method for important information about this certificate chain. + * + * @return the certificate chain for this credential's CredentialKey. + */ + public @NonNull abstract Collection<X509Certificate> getCredentialKeyCertificateChain(); + + /** + * Sets whether to allow using an authentication key which use count has been exceeded if no + * other key is available. This must be called prior to calling + * {@link #getEntries(byte[], Map, byte[], byte[])} or using a + * {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which references this + * object. + * + * By default this is set to true. + * + * @param allowUsingExhaustedKeys whether to allow using an authentication key which use count + * has been exceeded if no other key is available. + */ + public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys); + + /** + * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an + * operation handle. + * + * @hide + */ + public abstract long getCredstoreOperationHandle(); + + /** + * Retrieve data entries and associated data from this {@code IdentityCredential}. + * + * <p>If an access control check fails for one of the requested entries or if the entry + * doesn't exist, the entry is simply not returned. The application can detect this + * by using the {@link ResultData#getStatus(String, String)} method on each of the requested + * entries. + * + * <p>It is the responsibility of the calling application to know if authentication is needed + * and use e.g. {@link android.hardware.biometrics.BiometricPrompt}) to make the user + * authenticate using a {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which + * references this object. If needed, this must be done before calling + * {@link #getEntries(byte[], Map, byte[], byte[])}. + * + * <p>If this method returns successfully (i.e. without throwing an exception), it must not be + * called again on this instance. + * + * <p>If not {@code null} the {@code requestMessage} parameter must contain data for the request + * from the verifier. The content can be defined in the way appropriate for the credential, byt + * there are three requirements that must be met to work with this API: + * <ul> + * <li>The content must be a CBOR-encoded structure.</li> + * <li>The CBOR structure must be a map.</li> + * <li>The map must contain a tstr key "nameSpaces" whose value contains a map, as described in + * the example below.</li> + * </ul> + * + * <p>Here's an example of CBOR which conforms to this requirement: + * <pre> + * ItemsRequest = { + * ? "docType" : DocType, + * "nameSpaces" : NameSpaces, + * ? "RequestInfo" : {* tstr => any} ; Additional info the reader wants to provide + * } + * + * NameSpaces = { + * + NameSpace => DataElements ; Requested data elements for each NameSpace + * } + * + * NameSpace = tstr + * + * DataElements = { + * + DataElement => IntentToRetain + * } + * + * DataElement = tstr + * IntentToRetain = bool + * </pre> + * + * <p>If the {@code sessionTranscript} parameter is not {@code null}, it must contain CBOR + * data conforming to the following CDDL schema: + * + * <pre> + * SessionTranscript = [ + * DeviceEngagementBytes, + * EReaderKeyBytes + * ] + * + * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement) + * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub) + * </pre> + * + * <p>If the SessionTranscript is not empty, a COSE_Key structure for the public part + * of the key-pair previously generated by {@link #createEphemeralKeyPair()} must appear + * somewhere in {@code DeviceEngagement} and the X and Y coordinates must both be present + * in uncompressed form. + * + * <p>If {@code readerAuth} is not {@code null} it must be the bytes of a COSE_Sign1 + * structure as defined in RFC 8152. For the payload nil shall be used and the + * detached payload is the ReaderAuthentication CBOR described below. + * <pre> + * ReaderAuthentication = [ + * "ReaderAuthentication", + * SessionTranscript, + * ItemsRequestBytes + * ] + * + * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest) ; Bytes of ItemsRequest + * </pre> + * + * <p>The public key corresponding to the key used to made signature, can be + * found in the {@code x5chain} unprotected header element of the COSE_Sign1 + * structure (as as described in 'draft-ietf-cose-x509-04'). There will be at + * least one certificate in said element and there may be more (and if so, + * each certificate must be signed by its successor). + * + * <p>Data elements protected by reader authentication is returned if, and only if, they are + * mentioned in {@code requestMessage}, {@code requestMessage} is signed by the top-most + * certificate in {@code readerCertificateChain}, and the data element is configured + * with an {@link AccessControlProfile} with a {@link X509Certificate} in + * {@code readerCertificateChain}. + * + * <p>Note that only items referenced in {@code entriesToRequest} are returned - the + * {@code requestMessage} parameter is only used to for enforcing reader authentication. + * + * @param requestMessage If not {@code null}, must contain CBOR data conforming to + * the schema mentioned above. + * @param entriesToRequest The entries to request, organized as a map of namespace + * names with each value being a collection of data elements + * in the given namespace. + * @param readerSignature COSE_Sign1 structure as described above or {@code null} + * if reader authentication is not being used. + * @return A {@link ResultData} object containing entry data organized by namespace and a + * cryptographically authenticated representation of the same data. + * @throws SessionTranscriptMismatchException Thrown when trying use multiple different + * session transcripts in the same presentation + * session. + * @throws NoAuthenticationKeyAvailableException if authentication keys were never + * provisioned, the method + * {@link #setAvailableAuthenticationKeys(int, int)} + * was called with {@code keyCount} set to 0, + * the method + * {@link #setAllowUsingExhaustedKeys(boolean)} + * was called with {@code false} and all + * available authentication keys have been + * exhausted. + * @throws InvalidReaderSignatureException if the reader signature is invalid, or it + * doesn't contain a certificate chain, or if + * the signature failed to validate. + * @throws InvalidRequestMessageException if the requestMessage is malformed. + * @throws EphemeralPublicKeyNotFoundException if the ephemeral public key was not found in + * the session transcript. + */ + public abstract @NonNull ResultData getEntries( + @Nullable byte[] requestMessage, + @NonNull Map<String, Collection<String>> entriesToRequest, + @Nullable byte[] sessionTranscript, + @Nullable byte[] readerSignature) + throws SessionTranscriptMismatchException, NoAuthenticationKeyAvailableException, + InvalidReaderSignatureException, EphemeralPublicKeyNotFoundException, + InvalidRequestMessageException; + + /** + * Sets the number of dynamic authentication keys the {@code IdentityCredential} will maintain, + * and the number of times each should be used. + * + * <p>{@code IdentityCredential}s will select the least-used dynamic authentication key each + * time {@link #getEntries(byte[], Map, byte[], byte[])} is called. {@code IdentityCredential}s + * for which this method has not been called behave as though it had been called wit + * {@code keyCount} 0 and {@code maxUsesPerKey} 1. + * + * @param keyCount The number of active, certified dynamic authentication keys the + * {@code IdentityCredential} will try to keep available. This value + * must be non-negative. + * @param maxUsesPerKey The maximum number of times each of the keys will be used before it's + * eligible for replacement. This value must be greater than zero. + */ + public abstract void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey); + + /** + * Gets a collection of dynamic authentication keys that need certification. + * + * <p>When there aren't enough certified dynamic authentication keys, either because the key + * count has been increased or because one or more keys have reached their usage count, this + * method will generate replacement keys and certificates and return them for issuer + * certification. The issuer certificates and associated static authentication data must then + * be provided back to the {@code IdentityCredential} using + * {@link #storeStaticAuthenticationData(X509Certificate, byte[])}. + * + * <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey + * can be obtained using the {@link #getCredentialKeyCertificateChain()} method. + * + * @return A collection of X.509 certificates for dynamic authentication keys that need issuer + * certification. + */ + public @NonNull abstract Collection<X509Certificate> getAuthKeysNeedingCertification(); + + /** + * Store authentication data associated with a dynamic authentication key. + * + * This should only be called for an authenticated key returned by + * {@link #getAuthKeysNeedingCertification()}. + * + * @param authenticationKey The dynamic authentication key for which certification and + * associated static + * authentication data is being provided. + * @param staticAuthData Static authentication data provided by the issuer that validates + * the authenticity + * and integrity of the credential data fields. + * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized. + */ + public abstract void storeStaticAuthenticationData( + @NonNull X509Certificate authenticationKey, + @NonNull byte[] staticAuthData) + throws UnknownAuthenticationKeyException; + + /** + * Get the number of times the dynamic authentication keys have been used. + * + * @return int array of dynamic authentication key usage counts. + */ + public @NonNull abstract int[] getAuthenticationDataUsageCount(); +} diff --git a/identity/java/android/security/identity/IdentityCredentialException.java b/identity/java/android/security/identity/IdentityCredentialException.java new file mode 100644 index 000000000000..c8113803d5d3 --- /dev/null +++ b/identity/java/android/security/identity/IdentityCredentialException.java @@ -0,0 +1,44 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Base class for all Identity Credential exceptions. + */ +public class IdentityCredentialException extends Exception { + /** + * Constructs a new {@link IdentityCredentialException} exception. + * + * @param message the detail message. + */ + public IdentityCredentialException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link IdentityCredentialException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public IdentityCredentialException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } + +} diff --git a/identity/java/android/security/identity/IdentityCredentialStore.java b/identity/java/android/security/identity/IdentityCredentialStore.java new file mode 100644 index 000000000000..a1dfc77adb29 --- /dev/null +++ b/identity/java/android/security/identity/IdentityCredentialStore.java @@ -0,0 +1,186 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * An interface to a secure store for user identity documents. + * + * <p>This interface is deliberately fairly general and abstract. To the extent possible, + * specification of the message formats and semantics of communication with credential + * verification devices and issuing authorities (IAs) is out of scope. It provides the + * interface with secure storage but a credential-specific Android application will be + * required to implement the presentation and verification protocols and processes + * appropriate for the specific credential type. + * + * <p>Multiple credentials can be created. Each credential comprises:</p> + * <ul> + * <li>A document type, which is a string.</li> + * + * <li>A set of namespaces, which serve to disambiguate value names. It is recommended + * that namespaces be structured as reverse domain names so that IANA effectively serves + * as the namespace registrar.</li> + * + * <li>For each namespace, a set of name/value pairs, each with an associated set of + * access control profile IDs. Names are strings and values are typed and can be any + * value supported by <a href="http://cbor.io/">CBOR</a>.</li> + * + * <li>A set of access control profiles, each with a profile ID and a specification + * of the conditions which satisfy the profile's requirements.</li> + * + * <li>An asymmetric key pair which is used to authenticate the credential to the Issuing + * Authority, called the <em>CredentialKey</em>.</li> + * + * <li>A set of zero or more named reader authentication public keys, which are used to + * authenticate an authorized reader to the credential.</li> + * + * <li>A set of named signing keys, which are used to sign collections of values and session + * transcripts.</li> + * </ul> + * + * <p>Implementing support for user identity documents in secure storage requires dedicated + * hardware-backed support and may not always be available. + * + * <p>Two different credential stores exist - the <em>default</em> store and the + * <em>direct access</em> store. Most often credentials will be accessed through the default + * store but that requires that the Android device be powered up and fully functional. + * It is desirable to allow identity credential usage when the Android device's battery is too + * low to boot the Android operating system, so direct access to the secure hardware via NFC + * may allow data retrieval, if the secure hardware chooses to implement it. + * + * <p>Credentials provisioned to the direct access store should <strong>always</strong> use reader + * authentication to protect data elements. The reason for this is user authentication or user + * approval of data release is not possible when the device is off. + */ +public abstract class IdentityCredentialStore { + IdentityCredentialStore() {} + + /** + * Specifies that the cipher suite that will be used to secure communications between the reader + * is: + * + * <ul> + * <li>ECDHE with HKDF-SHA-256 for key agreement.</li> + * <li>AES-256 with GCM block mode for authenticated encryption (nonces are incremented by one + * for every message).</li> + * <li>ECDSA with SHA-256 for signing (used for signing session transcripts to defeat + * man-in-the-middle attacks), signing keys are not ephemeral. See {@link IdentityCredential} + * for details on reader and prover signing keys.</li> + * </ul> + * + * <p> + * At present this is the only supported cipher suite. + */ + public static final int CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1; + + /** + * Gets the default {@link IdentityCredentialStore}. + * + * @param context the application context. + * @return the {@link IdentityCredentialStore} or {@code null} if the device doesn't + * have hardware-backed support for secure storage of user identity documents. + */ + public static @Nullable IdentityCredentialStore getInstance(@NonNull Context context) { + return CredstoreIdentityCredentialStore.getInstance(context); + } + + /** + * Gets the {@link IdentityCredentialStore} for direct access. + * + * <p>Direct access requires specialized NFC hardware and may not be supported on all + * devices even if default store is available. Credentials provisioned to the direct + * access store should <strong>always</strong> use reader authentication to protect + * data elements. + * + * @param context the application context. + * @return the {@link IdentityCredentialStore} or {@code null} if direct access is not + * supported on this device. + */ + public static @Nullable IdentityCredentialStore getDirectAccessInstance(@NonNull + Context context) { + return CredstoreIdentityCredentialStore.getDirectAccessInstance(context); + } + + /** + * Gets a list of supported document types. + * + * <p>Only the direct-access store may restrict the kind of document types that can be used for + * credentials. The default store always supports any document type. + * + * @return The supported document types or the empty array if any document type is supported. + */ + public abstract @NonNull String[] getSupportedDocTypes(); + + /** + * Creates a new credential. + * + * @param credentialName The name used to identify the credential. + * @param docType The document type for the credential. + * @return A @{link WritableIdentityCredential} that can be used to create a new credential. + * @throws AlreadyPersonalizedException if a credential with the given name already exists. + * @throws DocTypeNotSupportedException if the given document type isn't supported by the store. + */ + public abstract @NonNull WritableIdentityCredential createCredential( + @NonNull String credentialName, @NonNull String docType) + throws AlreadyPersonalizedException, DocTypeNotSupportedException; + + /** + * Retrieve a named credential. + * + * @param credentialName the name of the credential to retrieve. + * @param cipherSuite the cipher suite to use for communicating with the verifier. + * @return The named credential, or null if not found. + */ + public abstract @Nullable IdentityCredential getCredentialByName(@NonNull String credentialName, + @Ciphersuite int cipherSuite) + throws CipherSuiteNotSupportedException; + + /** + * Delete a named credential. + * + * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey + * with payload set to {@code ProofOfDeletion} as defined below: + * + * <pre> + * ProofOfDeletion = [ + * "ProofOfDeletion", ; tstr + * tstr, ; DocType + * bool ; true if this is a test credential, should + * ; always be false. + * ] + * </pre> + * + * @param credentialName the name of the credential to delete. + * @return {@code null} if the credential was not found, the COSE_Sign1 data structure above + * if the credential was found and deleted. + */ + public abstract @Nullable byte[] deleteCredentialByName(@NonNull String credentialName); + + /** @hide */ + @IntDef(value = {CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256}) + @Retention(RetentionPolicy.SOURCE) + public @interface Ciphersuite { + } + +} diff --git a/identity/java/android/security/identity/InvalidReaderSignatureException.java b/identity/java/android/security/identity/InvalidReaderSignatureException.java new file mode 100644 index 000000000000..3f7027005830 --- /dev/null +++ b/identity/java/android/security/identity/InvalidReaderSignatureException.java @@ -0,0 +1,46 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if the reader signature is invalid, or it doesn't contain a certificate chain, or if the + * signature failed to validate. + */ +public class InvalidReaderSignatureException extends IdentityCredentialException { + /** + * Constructs a new {@link InvalidReaderSignatureException} exception. + * + * @param message the detail message. + */ + public InvalidReaderSignatureException(@NonNull String message) { + super(message); + } + + + /** + * Constructs a new {@link InvalidReaderSignatureException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public InvalidReaderSignatureException(@NonNull String message, + @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/InvalidRequestMessageException.java b/identity/java/android/security/identity/InvalidRequestMessageException.java new file mode 100644 index 000000000000..b0c073c33a8d --- /dev/null +++ b/identity/java/android/security/identity/InvalidRequestMessageException.java @@ -0,0 +1,46 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if message with the request doesn't satisfy the requirements documented in + * {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])}. + */ +public class InvalidRequestMessageException extends IdentityCredentialException { + /** + * Constructs a new {@link InvalidRequestMessageException} exception. + * + * @param message the detail message. + */ + public InvalidRequestMessageException(@NonNull String message) { + super(message); + } + + + /** + * Constructs a new {@link InvalidRequestMessageException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public InvalidRequestMessageException(@NonNull String message, + @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/MessageDecryptionException.java b/identity/java/android/security/identity/MessageDecryptionException.java new file mode 100644 index 000000000000..7a6169ea1d5b --- /dev/null +++ b/identity/java/android/security/identity/MessageDecryptionException.java @@ -0,0 +1,44 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown when failing to decrypt a message from the reader device. + */ +public class MessageDecryptionException extends IdentityCredentialException { + + /** + * Constructs a new {@link MessageDecryptionException} exception. + * + * @param message the detail message. + */ + public MessageDecryptionException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link MessageDecryptionException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public MessageDecryptionException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java b/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java new file mode 100644 index 000000000000..7f404037fbb1 --- /dev/null +++ b/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java @@ -0,0 +1,46 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if no dynamic authentication keys are available. + */ +public class NoAuthenticationKeyAvailableException extends IdentityCredentialException { + + /** + * Constructs a new {@link NoAuthenticationKeyAvailableException} exception. + * + * @param message the detail message. + */ + public NoAuthenticationKeyAvailableException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link NoAuthenticationKeyAvailableException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public NoAuthenticationKeyAvailableException(@NonNull String message, + @NonNull Throwable cause) { + super(message, cause); + } + +} diff --git a/identity/java/android/security/identity/PersonalizationData.java b/identity/java/android/security/identity/PersonalizationData.java new file mode 100644 index 000000000000..44370a1780f8 --- /dev/null +++ b/identity/java/android/security/identity/PersonalizationData.java @@ -0,0 +1,157 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; + +/** + * An object that holds personalization data. + * + * This data includes access control profiles and a set of data entries and values, grouped by + * namespace. + * + * This is used to provision data into a {@link WritableIdentityCredential}. + * + * @see WritableIdentityCredential#personalize + */ +public class PersonalizationData { + + private PersonalizationData() { + } + + private LinkedList<AccessControlProfile> mProfiles = new LinkedList<>(); + + private LinkedHashMap<String, NamespaceData> mNamespaces = new LinkedHashMap<>(); + + Collection<AccessControlProfile> getAccessControlProfiles() { + return Collections.unmodifiableCollection(mProfiles); + } + + Collection<String> getNamespaceNames() { + return Collections.unmodifiableCollection(mNamespaces.keySet()); + } + + NamespaceData getNamespaceData(String namespace) { + return mNamespaces.get(namespace); + } + + static class NamespaceData { + + private String mNamespace; + private LinkedHashMap<String, EntryData> mEntries = new LinkedHashMap<>(); + + private NamespaceData(String namespace) { + this.mNamespace = namespace; + } + + String getNamespaceName() { + return mNamespace; + } + + Collection<String> getEntryNames() { + return Collections.unmodifiableCollection(mEntries.keySet()); + } + + Collection<AccessControlProfileId> getAccessControlProfileIds(String name) { + EntryData value = mEntries.get(name); + if (value != null) { + return value.mAccessControlProfileIds; + } + return null; + } + + byte[] getEntryValue(String name) { + EntryData value = mEntries.get(name); + if (value != null) { + return value.mValue; + } + return null; + } + } + + private static class EntryData { + byte[] mValue; + Collection<AccessControlProfileId> mAccessControlProfileIds; + + EntryData(byte[] value, Collection<AccessControlProfileId> accessControlProfileIds) { + this.mValue = value; + this.mAccessControlProfileIds = accessControlProfileIds; + } + } + + /** + * A builder for {@link PersonalizationData}. + */ + public static final class Builder { + private PersonalizationData mData; + + /** + * Creates a new builder for a given namespace. + */ + public Builder() { + this.mData = new PersonalizationData(); + } + + /** + * Adds a new entry to the builder. + * + * @param namespace The namespace to use, e.g. {@code org.iso.18013-5.2019}. + * @param name The name of the entry, e.g. {@code height}. + * @param accessControlProfileIds A set of access control profiles to use. + * @param value The value to add, in CBOR encoding. + * @return The builder. + */ + public @NonNull Builder setEntry(@NonNull String namespace, @NonNull String name, + @NonNull Collection<AccessControlProfileId> accessControlProfileIds, + @NonNull byte[] value) { + NamespaceData namespaceData = mData.mNamespaces.get(namespace); + if (namespaceData == null) { + namespaceData = new NamespaceData(namespace); + mData.mNamespaces.put(namespace, namespaceData); + } + // TODO: validate/verify that value is proper CBOR. + namespaceData.mEntries.put(name, new EntryData(value, accessControlProfileIds)); + return this; + } + + /** + * Adds a new access control profile to the builder. + * + * @param profile The access control profile. + * @return The builder. + */ + public @NonNull Builder addAccessControlProfile(@NonNull AccessControlProfile profile) { + mData.mProfiles.add(profile); + return this; + } + + /** + * Creates a new {@link PersonalizationData} with all the entries added to the builder. + * + * @return A new {@link PersonalizationData} instance. + */ + public @NonNull PersonalizationData build() { + return mData; + } + } + +} diff --git a/identity/java/android/security/identity/ResultData.java b/identity/java/android/security/identity/ResultData.java new file mode 100644 index 000000000000..0982c8a4ab31 --- /dev/null +++ b/identity/java/android/security/identity/ResultData.java @@ -0,0 +1,224 @@ +/* + * Copyright 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.security.identity; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.lang.annotation.Retention; +import java.util.Collection; + +/** + * An object that contains the result of retrieving data from a credential. This is used to return + * data requested from a {@link IdentityCredential}. + */ +public abstract class ResultData { + + /** Value was successfully retrieved. */ + public static final int STATUS_OK = 0; + + /** Requested entry does not exist. */ + public static final int STATUS_NO_SUCH_ENTRY = 1; + + /** Requested entry was not requested. */ + public static final int STATUS_NOT_REQUESTED = 2; + + /** Requested entry wasn't in the request message. */ + public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3; + + /** The requested entry was not retrieved because user authentication wasn't performed. */ + public static final int STATUS_USER_AUTHENTICATION_FAILED = 4; + + /** The requested entry was not retrieved because reader authentication wasn't performed. */ + public static final int STATUS_READER_AUTHENTICATION_FAILED = 5; + + /** + * The requested entry was not retrieved because it was configured without any access + * control profile. + */ + public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6; + + /** + * @hide + */ + protected ResultData() {} + + /** + * Returns a CBOR structure containing the retrieved data. + * + * <p>This structure - along with the session transcript - may be cryptographically + * authenticated to prove to the reader that the data is from a trusted credential and + * {@link #getMessageAuthenticationCode()} can be used to get a MAC. + * + * <p>The CBOR structure which is cryptographically authenticated is the + * {@code DeviceAuthentication} structure according to the following + * <a href="https://tools.ietf.org/html/draft-ietf-cbor-cddl-06">CDDL</a> schema: + * + * <pre> + * DeviceAuthentication = [ + * "DeviceAuthentication", + * SessionTranscript, + * DocType, + * DeviceNameSpacesBytes + * ] + * + * DocType = tstr + * + * SessionTranscript = [ + * DeviceEngagementBytes, + * EReaderKeyBytes + * ] + * + * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement) + * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub) + * + * DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces) + * </pre> + * + * where + * + * <pre> + * DeviceNameSpaces = { + * * NameSpace => DeviceSignedItems + * } + * + * DeviceSignedItems = { + * + DataItemName => DataItemValue + * } + * + * NameSpace = tstr + * DataItemName = tstr + * DataItemValue = any + * </pre> + * + * <p>The returned data is the binary encoding of the {@code DeviceNameSpaces} structure + * as defined above. + * + * @return The bytes of the {@code DeviceNameSpaces} CBOR structure. + */ + public abstract @NonNull byte[] getAuthenticatedData(); + + /** + * Returns a message authentication code over the data returned by + * {@link #getAuthenticatedData}, to prove to the reader that the data is from a trusted + * credential. + * + * <p>The MAC proves to the reader that the data is from a trusted credential. This code is + * produced by using the key agreement and key derivation function from the ciphersuite + * with the authentication private key and the reader ephemeral public key to compute a + * shared message authentication code (MAC) key, then using the MAC function from the + * ciphersuite to compute a MAC of the authenticated data. + * + * <p>If the {@code sessionTranscript} parameter passed to + * {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])} was {@code null} + * or the reader ephmeral public key was never set using + * {@link IdentityCredential#setReaderEphemeralPublicKey(PublicKey)}, no message + * authencation code will be produced and this method will return {@code null}. + * + * @return A COSE_Mac0 structure with the message authentication code as described above + * or {@code null} if the conditions specified above are not met. + */ + public abstract @Nullable byte[] getMessageAuthenticationCode(); + + /** + * Returns the static authentication data associated with the dynamic authentication + * key used to sign or MAC the data returned by {@link #getAuthenticatedData()}. + * + * @return The static authentication data associated with dynamic authentication key used to + * MAC the data. + */ + public abstract @NonNull byte[] getStaticAuthenticationData(); + + /** + * Gets the names of namespaces with retrieved entries. + * + * @return collection of name of namespaces containing retrieved entries. May be empty if no + * data was retrieved. + */ + public abstract @NonNull Collection<String> getNamespaceNames(); + + /** + * Get the names of all entries. + * + * This includes the name of entries that wasn't successfully retrieved. + * + * @param namespaceName the namespace name to get entries for. + * @return A collection of names or {@code null} if there are no entries for the given + * namespace. + */ + public abstract @Nullable Collection<String> getEntryNames(@NonNull String namespaceName); + + /** + * Get the names of all entries that was successfully retrieved. + * + * This only return entries for which {@link #getStatus(String, String)} will return + * {@link #STATUS_OK}. + * + * @param namespaceName the namespace name to get entries for. + * @return A collection of names or {@code null} if there are no entries for the given + * namespace. + */ + public abstract @Nullable Collection<String> getRetrievedEntryNames( + @NonNull String namespaceName); + + /** + * Gets the status of an entry. + * + * This returns {@link #STATUS_OK} if the value was retrieved, {@link #STATUS_NO_SUCH_ENTRY} + * if the given entry wasn't retrieved, {@link #STATUS_NOT_REQUESTED} if it wasn't requested, + * {@link #STATUS_NOT_IN_REQUEST_MESSAGE} if the request message was set but the entry wasn't + * present in the request message, + * {@link #STATUS_USER_AUTHENTICATION_FAILED} if the value + * wasn't retrieved because the necessary user authentication wasn't performed, + * {@link #STATUS_READER_AUTHENTICATION_FAILED} if the supplied reader certificate chain + * didn't match the set of certificates the entry was provisioned with, or + * {@link #STATUS_NO_ACCESS_CONTROL_PROFILES} if the entry was configured without any + * access control profiles. + * + * @param namespaceName the namespace name of the entry. + * @param name the name of the entry to get the value for. + * @return the status indicating whether the value was retrieved and if not, why. + */ + @Status + public abstract int getStatus(@NonNull String namespaceName, @NonNull String name); + + /** + * Gets the raw CBOR data for the value of an entry. + * + * This should only be called on an entry for which the {@link #getStatus(String, String)} + * method returns {@link #STATUS_OK}. + * + * @param namespaceName the namespace name of the entry. + * @param name the name of the entry to get the value for. + * @return the raw CBOR data or {@code null} if no entry with the given name exists. + */ + public abstract @Nullable byte[] getEntry(@NonNull String namespaceName, @NonNull String name); + + /** + * The type of the entry status. + * @hide + */ + @Retention(SOURCE) + @IntDef({STATUS_OK, STATUS_NO_SUCH_ENTRY, STATUS_NOT_REQUESTED, STATUS_NOT_IN_REQUEST_MESSAGE, + STATUS_USER_AUTHENTICATION_FAILED, STATUS_READER_AUTHENTICATION_FAILED, + STATUS_NO_ACCESS_CONTROL_PROFILES}) + public @interface Status { + } +} diff --git a/identity/java/android/security/identity/SessionTranscriptMismatchException.java b/identity/java/android/security/identity/SessionTranscriptMismatchException.java new file mode 100644 index 000000000000..8c2406043f67 --- /dev/null +++ b/identity/java/android/security/identity/SessionTranscriptMismatchException.java @@ -0,0 +1,44 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown when trying use multiple different session transcripts in the same presentation session. + */ +public class SessionTranscriptMismatchException extends IdentityCredentialException { + + /** + * Constructs a new {@link SessionTranscriptMismatchException} exception. + * + * @param message the detail message. + */ + public SessionTranscriptMismatchException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link SessionTranscriptMismatchException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public SessionTranscriptMismatchException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/UnknownAuthenticationKeyException.java b/identity/java/android/security/identity/UnknownAuthenticationKeyException.java new file mode 100644 index 000000000000..f454b2ce2af9 --- /dev/null +++ b/identity/java/android/security/identity/UnknownAuthenticationKeyException.java @@ -0,0 +1,43 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if trying to certify an unknown dynamic authentication key. + */ +public class UnknownAuthenticationKeyException extends IdentityCredentialException { + /** + * Constructs a new {@link UnknownAuthenticationKeyException} exception. + * + * @param message the detail message. + */ + public UnknownAuthenticationKeyException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link UnknownAuthenticationKeyException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public UnknownAuthenticationKeyException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/Util.java b/identity/java/android/security/identity/Util.java new file mode 100644 index 000000000000..6eefeb8f3f2a --- /dev/null +++ b/identity/java/android/security/identity/Util.java @@ -0,0 +1,140 @@ +/* + * Copyright 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.security.identity; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECPoint; +import java.util.Collection; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +class Util { + private static final String TAG = "Util"; + + static int[] integerCollectionToArray(Collection<Integer> collection) { + int[] result = new int[collection.size()]; + int n = 0; + for (int item : collection) { + result[n++] = item; + } + return result; + } + + static byte[] stripLeadingZeroes(byte[] value) { + int n = 0; + while (n < value.length && value[n] == 0) { + n++; + } + int newLen = value.length - n; + byte[] ret = new byte[newLen]; + int m = 0; + while (n < value.length) { + ret[m++] = value[n++]; + } + return ret; + } + + static byte[] publicKeyEncodeUncompressedForm(PublicKey publicKey) { + ECPoint w = ((ECPublicKey) publicKey).getW(); + // X and Y are always positive so for interop we remove any leading zeroes + // inserted by the BigInteger encoder. + byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray()); + byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray()); + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(0x04); + baos.write(x); + baos.write(y); + return baos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("Unexpected IOException", e); + } + } + + /** + * Computes an HKDF. + * + * This is based on https://github.com/google/tink/blob/master/java/src/main/java/com/google + * /crypto/tink/subtle/Hkdf.java + * which is also Copyright (c) Google and also licensed under the Apache 2 license. + * + * @param macAlgorithm the MAC algorithm used for computing the Hkdf. I.e., "HMACSHA1" or + * "HMACSHA256". + * @param ikm the input keying material. + * @param salt optional salt. A possibly non-secret random value. If no salt is + * provided (i.e. if + * salt has length 0) then an array of 0s of the same size as the hash + * digest is used as salt. + * @param info optional context and application specific information. + * @param size The length of the generated pseudorandom string in bytes. The maximal + * size is + * 255.DigestSize, where DigestSize is the size of the underlying HMAC. + * @return size pseudorandom bytes. + */ + static byte[] computeHkdf( + String macAlgorithm, final byte[] ikm, final byte[] salt, final byte[] info, int size) { + Mac mac = null; + try { + mac = Mac.getInstance(macAlgorithm); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("No such algorithm: " + macAlgorithm, e); + } + if (size > 255 * mac.getMacLength()) { + throw new RuntimeException("size too large"); + } + try { + if (salt == null || salt.length == 0) { + // According to RFC 5869, Section 2.2 the salt is optional. If no salt is provided + // then HKDF uses a salt that is an array of zeros of the same length as the hash + // digest. + mac.init(new SecretKeySpec(new byte[mac.getMacLength()], macAlgorithm)); + } else { + mac.init(new SecretKeySpec(salt, macAlgorithm)); + } + byte[] prk = mac.doFinal(ikm); + byte[] result = new byte[size]; + int ctr = 1; + int pos = 0; + mac.init(new SecretKeySpec(prk, macAlgorithm)); + byte[] digest = new byte[0]; + while (true) { + mac.update(digest); + mac.update(info); + mac.update((byte) ctr); + digest = mac.doFinal(); + if (pos + digest.length < size) { + System.arraycopy(digest, 0, result, pos, digest.length); + pos += digest.length; + ctr++; + } else { + System.arraycopy(digest, 0, result, pos, size - pos); + break; + } + } + return result; + } catch (InvalidKeyException e) { + throw new RuntimeException("Error MACing", e); + } + } + +} diff --git a/identity/java/android/security/identity/WritableIdentityCredential.java b/identity/java/android/security/identity/WritableIdentityCredential.java new file mode 100644 index 000000000000..e2a389bfd4da --- /dev/null +++ b/identity/java/android/security/identity/WritableIdentityCredential.java @@ -0,0 +1,116 @@ +/* + * Copyright 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.security.identity; + +import android.annotation.NonNull; + +import java.security.cert.X509Certificate; +import java.util.Collection; + +/** + * Class used to personalize a new identity credential. + * + * <p>Credentials cannot be updated or modified after creation; any changes require deletion and + * re-creation. + * + * Use {@link IdentityCredentialStore#createCredential(String, String)} to create a new credential. + */ +public abstract class WritableIdentityCredential { + /** + * @hide + */ + protected WritableIdentityCredential() {} + + /** + * Generates and returns an X.509 certificate chain for the CredentialKey which identifies this + * credential to the issuing authority. The certificate contains an + * <a href="https://source.android.com/security/keystore/attestation">Android Keystore</a> + * attestation extension which describes the key and the security hardware in which it lives. + * + * <p>Additionally, the attestation extension will contain the tag TODO_IC_KEY which indicates + * it is an Identity Credential key (which can only sign/MAC very specific messages) and not + * an Android Keystore key (which can be used to sign/MAC anything). + * + * <p>The issuer <b>MUST</b> carefully examine this certificate chain including (but not + * limited to) checking that the root certificate is well-known, the tag TODO_IC_KEY is + * present, the passed in challenge is present, the device has verified boot enabled, that each + * certificate in the chain is signed by its successor, that none of the certificates have been + * revoked and so on. + * + * <p>It is not strictly necessary to use this method to provision a credential if the issuing + * authority doesn't care about the nature of the security hardware. If called, however, this + * method must be called before {@link #personalize(PersonalizationData)}. + * + * @param challenge is a byte array whose contents should be unique, fresh and provided by + * the issuing authority. The value provided is embedded in the attestation + * extension and enables the issuing authority to verify that the attestation + * certificate is fresh. + * @return the X.509 certificate for this credential's CredentialKey. + */ + public abstract @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain( + @NonNull byte[] challenge); + + /** + * Stores all of the data in the credential, with the specified access control profiles. + * + * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey with payload + * set to {@code ProofOfProvisioning} as defined below. + * + * <pre> + * ProofOfProvisioning = [ + * "ProofOfProvisioning", ; tstr + * tstr, ; DocType + * [ * AccessControlProfile ], + * ProvisionedData, + * bool ; true if this is a test credential, should + * ; always be false. + * ] + * + * AccessControlProfile = { + * "id": uint, + * ? "readerCertificate" : bstr, + * ? ( + * "userAuthenticationRequired" : bool, + * "timeoutMillis" : uint, + * ) + * } + * + * ProvisionedData = { + * * Namespace => [ + Entry ] + * }, + * + * Namespace = tstr + * + * Entry = { + * "name" : tstr, + * "value" : any, + * "accessControlProfiles" : [ * uint ], + * } + * </pre> + * + * <p>This data structure provides a guarantee to the issuer about the data which may be + * returned in the CBOR returned by + * {@link ResultData#getAuthenticatedData()} during a credential + * presentation. + * + * @param personalizationData The data to provision, including access control profiles + * and data elements and their values, grouped into namespaces. + * @return A COSE_Sign1 data structure, see above. + */ + public abstract @NonNull byte[] personalize( + @NonNull PersonalizationData personalizationData); +} diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java index fad7d8062a22..7282bcfe4445 100644 --- a/keystore/java/android/security/Credentials.java +++ b/keystore/java/android/security/Credentials.java @@ -16,7 +16,7 @@ package android.security; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.org.bouncycastle.util.io.pem.PemObject; import com.android.org.bouncycastle.util.io.pem.PemReader; diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java index a50ff7984341..af188a95c929 100644 --- a/keystore/java/android/security/GateKeeper.java +++ b/keystore/java/android/security/GateKeeper.java @@ -16,7 +16,7 @@ package android.security; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index c0a04220cfe7..e9bc8026d25e 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -16,10 +16,10 @@ package android.security; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.Application; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.face.FaceManager; @@ -31,7 +31,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; -import android.security.KeyStoreException; import android.security.keymaster.ExportResult; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java index c6515efd2c61..feb6101cb080 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java @@ -176,7 +176,7 @@ abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreC KeyStore keyStore, IBinder operationToken) { KeyStoreCryptoOperationStreamer streamer = new KeyStoreCryptoOperationChunkedStreamer( new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( - keyStore, operationToken)); + keyStore, operationToken), 0); if (isEncrypting()) { return streamer; } else { @@ -191,7 +191,7 @@ abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreC protected final KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer( KeyStore keyStore, IBinder operationToken) { return new KeyStoreCryptoOperationChunkedStreamer( - new AdditionalAuthenticationDataStream(keyStore, operationToken)); + new AdditionalAuthenticationDataStream(keyStore, operationToken), 0); } @Override diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java index 5bcb34a67a54..ccc3153749fb 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java @@ -299,7 +299,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor KeyStore keyStore, IBinder operationToken) { return new KeyStoreCryptoOperationChunkedStreamer( new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( - keyStore, operationToken)); + keyStore, operationToken), 0); } /** diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java index 234615d9c81d..8be85d6827f4 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java @@ -17,7 +17,7 @@ package android.security.keystore; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.security.KeyStore; import android.security.keymaster.ExportResult; import android.security.keymaster.KeyCharacteristics; diff --git a/keystore/java/android/security/keystore/ArrayUtils.java b/keystore/java/android/security/keystore/ArrayUtils.java index 26172d276b8c..f519c7cdd3d2 100644 --- a/keystore/java/android/security/keystore/ArrayUtils.java +++ b/keystore/java/android/security/keystore/ArrayUtils.java @@ -55,6 +55,34 @@ public abstract class ArrayUtils { } } + /** + * Copies a subset of the source array to the destination array. + * Length will be limited to the bounds of source and destination arrays. + * The length actually copied is returned, which will be <= length argument. + * @param src is the source array + * @param srcOffset is the offset in the source array. + * @param dst is the destination array. + * @param dstOffset is the offset in the destination array. + * @param length is the length to be copied from source to destination array. + * @return The length actually copied from source array. + */ + public static int copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int length) { + if (dst == null || src == null) { + return 0; + } + if (length > dst.length - dstOffset) { + length = dst.length - dstOffset; + } + if (length > src.length - srcOffset) { + length = src.length - srcOffset; + } + if (length <= 0) { + return 0; + } + System.arraycopy(src, srcOffset, dst, dstOffset, length); + return length; + } + public static byte[] subarray(byte[] arr, int offset, int len) { if (len == 0) { return EmptyArray.BYTE; diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index e3f43efff72b..630a6dd081a3 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -20,8 +20,8 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; import android.security.GateKeeper; diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java index 75bea26aecef..2c0f40d528d2 100644 --- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java +++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java @@ -24,19 +24,20 @@ import android.security.keymaster.OperationResult; import libcore.util.EmptyArray; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.security.ProviderException; - /** * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's * {@code update} and {@code finish} operations. * - * <p>The helper abstracts away to issues that need to be solved in most code that uses KeyStore's + * <p>The helper abstracts away issues that need to be solved in most code that uses KeyStore's * update and finish operations. Firstly, KeyStore's update operation can consume only a limited * amount of data in one go because the operations are marshalled via Binder. Secondly, the update * operation may consume less data than provided, in which case the caller has to buffer the - * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and + * remainder for next time. Thirdly, when the input is smaller than a threshold, skipping update + * and passing input data directly to final improves performance. This threshold is configurable; + * using a threshold <= 1 causes the helper act eagerly, which may be required for some types of + * operations (e.g. ciphers). + * + * <p>The helper exposes {@link #update(byte[], int, int) update} and * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to * conveniently implement various JCA crypto primitives. * @@ -67,240 +68,122 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS // Binder buffer is about 1MB, but it's shared between all active transactions of the process. // Thus, it's safer to use a much smaller upper bound. - private static final int DEFAULT_MAX_CHUNK_SIZE = 64 * 1024; + private static final int DEFAULT_CHUNK_SIZE_MAX = 64 * 1024; + // The chunk buffer will be sent to update until its size under this threshold. + // This threshold should be <= the max input allowed for finish. + // Setting this threshold <= 1 will effectivley disable buffering between updates. + private static final int DEFAULT_CHUNK_SIZE_THRESHOLD = 2 * 1024; private final Stream mKeyStoreStream; - private final int mMaxChunkSize; - - private byte[] mBuffered = EmptyArray.BYTE; - private int mBufferedOffset; - private int mBufferedLength; + private final int mChunkSizeMax; + private final int mChunkSizeThreshold; + private final byte[] mChunk; + private int mChunkLength = 0; private long mConsumedInputSizeBytes; private long mProducedOutputSizeBytes; - public KeyStoreCryptoOperationChunkedStreamer(Stream operation) { - this(operation, DEFAULT_MAX_CHUNK_SIZE); + KeyStoreCryptoOperationChunkedStreamer(Stream operation) { + this(operation, DEFAULT_CHUNK_SIZE_THRESHOLD, DEFAULT_CHUNK_SIZE_MAX); } - public KeyStoreCryptoOperationChunkedStreamer(Stream operation, int maxChunkSize) { + KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold) { + this(operation, chunkSizeThreshold, DEFAULT_CHUNK_SIZE_MAX); + } + + KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold, + int chunkSizeMax) { mKeyStoreStream = operation; - mMaxChunkSize = maxChunkSize; + mChunkSizeMax = chunkSizeMax; + if (chunkSizeThreshold <= 0) { + mChunkSizeThreshold = 1; + } else if (chunkSizeThreshold > chunkSizeMax) { + mChunkSizeThreshold = chunkSizeMax; + } else { + mChunkSizeThreshold = chunkSizeThreshold; + } + mChunk = new byte[mChunkSizeMax]; } - @Override public byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException { - if (inputLength == 0) { + if (inputLength == 0 || input == null) { // No input provided return EmptyArray.BYTE; } + if (inputLength < 0 || inputOffset < 0 || (inputOffset + inputLength) > input.length) { + throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR, + "Input offset and length out of bounds of input array"); + } - ByteArrayOutputStream bufferedOutput = null; + byte[] output = EmptyArray.BYTE; - while (inputLength > 0) { - byte[] chunk; - int inputBytesInChunk; - if ((mBufferedLength + inputLength) > mMaxChunkSize) { - // Too much input for one chunk -- extract one max-sized chunk and feed it into the - // update operation. - inputBytesInChunk = mMaxChunkSize - mBufferedLength; - chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength, - input, inputOffset, inputBytesInChunk); - } else { - // All of available input fits into one chunk. - if ((mBufferedLength == 0) && (inputOffset == 0) - && (inputLength == input.length)) { - // Nothing buffered and all of input array needs to be fed into the update - // operation. - chunk = input; - inputBytesInChunk = input.length; - } else { - // Need to combine buffered data with input data into one array. - inputBytesInChunk = inputLength; - chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength, - input, inputOffset, inputBytesInChunk); - } - } - // Update input array references to reflect that some of its bytes are now in mBuffered. - inputOffset += inputBytesInChunk; - inputLength -= inputBytesInChunk; - mConsumedInputSizeBytes += inputBytesInChunk; + while (inputLength > 0 || mChunkLength >= mChunkSizeThreshold) { + int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength, + inputLength); + inputLength -= inputConsumed; + inputOffset += inputConsumed; + mChunkLength += inputConsumed; + mConsumedInputSizeBytes += inputConsumed; - OperationResult opResult = mKeyStoreStream.update(chunk); - if (opResult == null) { - throw new KeyStoreConnectException(); - } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw KeyStore.getKeyStoreException(opResult.resultCode); + if (mChunkLength > mChunkSizeMax) { + throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH, + "Chunk size exceeded max chunk size. Max: " + mChunkSizeMax + + " Actual: " + mChunkLength); } - if (opResult.inputConsumed == chunk.length) { - // The whole chunk was consumed - mBuffered = EmptyArray.BYTE; - mBufferedOffset = 0; - mBufferedLength = 0; - } else if (opResult.inputConsumed <= 0) { - // Nothing was consumed. More input needed. - if (inputLength > 0) { - // More input is available, but it wasn't included into the previous chunk - // because the chunk reached its maximum permitted size. - // Shouldn't have happened. + if (mChunkLength >= mChunkSizeThreshold) { + OperationResult opResult = mKeyStoreStream.update( + ArrayUtils.subarray(mChunk, 0, mChunkLength)); + + if (opResult == null) { + throw new KeyStoreConnectException(); + } else if (opResult.resultCode != KeyStore.NO_ERROR) { + throw KeyStore.getKeyStoreException(opResult.resultCode); + } + if (opResult.inputConsumed <= 0) { + throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH, + "Keystore consumed 0 of " + mChunkLength + " bytes provided."); + } else if (opResult.inputConsumed > mChunkLength) { throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR, - "Keystore consumed nothing from max-sized chunk: " + chunk.length - + " bytes"); + "Keystore consumed more input than provided. Provided: " + + mChunkLength + ", consumed: " + opResult.inputConsumed); } - mBuffered = chunk; - mBufferedOffset = 0; - mBufferedLength = chunk.length; - } else if (opResult.inputConsumed < chunk.length) { - // The chunk was consumed only partially -- buffer the rest of the chunk - mBuffered = chunk; - mBufferedOffset = opResult.inputConsumed; - mBufferedLength = chunk.length - opResult.inputConsumed; - } else { - throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR, - "Keystore consumed more input than provided. Provided: " + chunk.length - + ", consumed: " + opResult.inputConsumed); - } + mChunkLength -= opResult.inputConsumed; - if ((opResult.output != null) && (opResult.output.length > 0)) { - if (inputLength + mBufferedLength > 0) { - // More output might be produced in this loop -- buffer the current output - if (bufferedOutput == null) { - bufferedOutput = new ByteArrayOutputStream(); - } - try { - bufferedOutput.write(opResult.output); - } catch (IOException e) { - throw new ProviderException("Failed to buffer output", e); - } - } else { - // No more output will be produced in this loop - byte[] result; - if (bufferedOutput == null) { - // No previously buffered output - result = opResult.output; - } else { - // There was some previously buffered output - try { - bufferedOutput.write(opResult.output); - } catch (IOException e) { - throw new ProviderException("Failed to buffer output", e); - } - result = bufferedOutput.toByteArray(); - } - mProducedOutputSizeBytes += result.length; - return result; + if (mChunkLength > 0) { + // Partialy consumed, shift chunk contents + ArrayUtils.copy(mChunk, opResult.inputConsumed, mChunk, 0, mChunkLength); } - } - } - byte[] result; - if (bufferedOutput == null) { - // No output produced - result = EmptyArray.BYTE; - } else { - result = bufferedOutput.toByteArray(); + if ((opResult.output != null) && (opResult.output.length > 0)) { + // Output was produced + mProducedOutputSizeBytes += opResult.output.length; + output = ArrayUtils.concat(output, opResult.output); + } + } } - mProducedOutputSizeBytes += result.length; - return result; + return output; } - @Override public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature, byte[] additionalEntropy) throws KeyStoreException { - if (inputLength == 0) { - // No input provided -- simplify the rest of the code - input = EmptyArray.BYTE; - inputOffset = 0; - } - - // Flush all buffered input and provided input into keystore/keymaster. byte[] output = update(input, inputOffset, inputLength); - output = ArrayUtils.concat(output, flush()); + byte[] finalChunk = ArrayUtils.subarray(mChunk, 0, mChunkLength); + OperationResult opResult = mKeyStoreStream.finish(finalChunk, signature, additionalEntropy); - OperationResult opResult = mKeyStoreStream.finish(EmptyArray.BYTE, signature, - additionalEntropy); if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { throw KeyStore.getKeyStoreException(opResult.resultCode); } - mProducedOutputSizeBytes += opResult.output.length; - - return ArrayUtils.concat(output, opResult.output); - } - - public byte[] flush() throws KeyStoreException { - if (mBufferedLength <= 0) { - return EmptyArray.BYTE; - } - - // Keep invoking the update operation with remaining buffered data until either all of the - // buffered data is consumed or until update fails to consume anything. - ByteArrayOutputStream bufferedOutput = null; - while (mBufferedLength > 0) { - byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength); - OperationResult opResult = mKeyStoreStream.update(chunk); - if (opResult == null) { - throw new KeyStoreConnectException(); - } else if (opResult.resultCode != KeyStore.NO_ERROR) { - throw KeyStore.getKeyStoreException(opResult.resultCode); - } - - if (opResult.inputConsumed <= 0) { - // Nothing was consumed. Break out of the loop to avoid an infinite loop. - break; - } - - if (opResult.inputConsumed >= chunk.length) { - // All of the input was consumed - mBuffered = EmptyArray.BYTE; - mBufferedOffset = 0; - mBufferedLength = 0; - } else { - // Some of the input was not consumed - mBuffered = chunk; - mBufferedOffset = opResult.inputConsumed; - mBufferedLength = chunk.length - opResult.inputConsumed; - } - - if (opResult.inputConsumed > chunk.length) { - throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR, - "Keystore consumed more input than provided. Provided: " - + chunk.length + ", consumed: " + opResult.inputConsumed); - } - - if ((opResult.output != null) && (opResult.output.length > 0)) { - // Some output was produced by this update operation - if (bufferedOutput == null) { - // No output buffered yet. - if (mBufferedLength == 0) { - // No more output will be produced by this flush operation - mProducedOutputSizeBytes += opResult.output.length; - return opResult.output; - } else { - // More output might be produced by this flush operation -- buffer output. - bufferedOutput = new ByteArrayOutputStream(); - } - } - // Buffer the output from this update operation - try { - bufferedOutput.write(opResult.output); - } catch (IOException e) { - throw new ProviderException("Failed to buffer output", e); - } - } - } + // If no error, assume all input consumed + mConsumedInputSizeBytes += finalChunk.length; - if (mBufferedLength > 0) { - throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH, - "Keystore failed to consume last " - + ((mBufferedLength != 1) ? (mBufferedLength + " bytes") : "byte") - + " of input"); + if ((opResult.output != null) && (opResult.output.length > 0)) { + mProducedOutputSizeBytes += opResult.output.length; + output = ArrayUtils.concat(output, opResult.output); } - byte[] result = (bufferedOutput != null) ? bufferedOutput.toByteArray() : EmptyArray.BYTE; - mProducedOutputSizeBytes += result.length; - return result; + return output; } @Override diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 4c08a3829934..98de9c3ea88e 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -25,11 +25,6 @@ cc_defaults { // GCC false-positives on this warning, and since we -Werror that's // a problem "-Wno-free-nonheap-object", - - // Clang is producing non-determistic binary when the new pass manager is - // enabled. Disable the new PM as a temporary workaround. - // b/142372146 - "-fno-experimental-new-pass-manager", ], include_dirs: [ diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 219d04055eae..c21bdca3db77 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -219,7 +219,7 @@ Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette) : SkPixelRef(info.width(), info.height(), nullptr, - bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride()) + bytesPerPixel(buffer->getPixelFormat()) * (buffer->getStride() > 0 ? buffer->getStride() : buffer->getWidth())) , mInfo(validateAlpha(info)) , mPixelStorageType(PixelStorageType::Hardware) , mPalette(palette) diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java index f3c2a1684cda..8c40338e80fc 100644 --- a/location/java/android/location/Country.java +++ b/location/java/android/location/Country.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java index ae139499eeb2..e344b820ca2a 100644 --- a/location/java/android/location/CountryDetector.java +++ b/location/java/android/location/CountryDetector.java @@ -16,10 +16,8 @@ package android.location; -import java.util.HashMap; - import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; @@ -27,6 +25,8 @@ import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import java.util.HashMap; + /** * This class provides access to the system country detector service. This * service allows applications to obtain the country that the user is in. diff --git a/location/java/android/location/CountryListener.java b/location/java/android/location/CountryListener.java index 70a83c5acdd9..eb67205f4de9 100644 --- a/location/java/android/location/CountryListener.java +++ b/location/java/android/location/CountryListener.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The listener for receiving the notification when the country is detected or diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java index 45d92ee7cc34..1c6e9b6e1836 100644 --- a/location/java/android/location/GeocoderParams.java +++ b/location/java/android/location/GeocoderParams.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java index 9570b26452e4..af57bfd30984 100644 --- a/location/java/android/location/Geofence.java +++ b/location/java/android/location/Geofence.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java index 609a15e1be7e..8a5edc41a774 100644 --- a/location/java/android/location/GpsStatus.java +++ b/location/java/android/location/GpsStatus.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.util.SparseArray; diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index 9c36d76cf370..6f12c78e8621 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -18,7 +18,7 @@ package android.location; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.Parcel; diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 7b24f44823d0..f17f7483a838 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -30,8 +30,8 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index 0902acf176d4..adea73d25922 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -22,7 +22,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index f9b2fe057995..9846436b3ac8 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -19,6 +19,7 @@ package com.android.internal.location; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -37,8 +38,6 @@ import com.android.internal.R; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.telephony.GsmAlphabet; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.UnsupportedEncodingException; import java.util.concurrent.TimeUnit; @@ -126,7 +125,7 @@ public class GpsNetInitiatedHandler { public static class GpsNiNotification { - @android.annotation.UnsupportedAppUsage + @android.compat.annotation.UnsupportedAppUsage public GpsNiNotification() { } public int notificationId; diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java index 155f788cb33e..c23f49976799 100644 --- a/location/java/com/android/internal/location/ProviderRequest.java +++ b/location/java/com/android/internal/location/ProviderRequest.java @@ -16,7 +16,7 @@ package com.android.internal.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.location.LocationRequest; import android.os.Parcel; import android.os.Parcelable; diff --git a/media/OWNERS b/media/OWNERS index 8bd037a14150..be605831a24b 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -5,6 +5,7 @@ elaurent@google.com etalvala@google.com gkasten@google.com hdmoon@google.com +hkuang@google.com hunga@google.com insun@google.com jaewan@google.com diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java index 5088798a2910..3cb224dd58cd 100644 --- a/media/java/android/media/AmrInputStream.java +++ b/media/java/android/media/AmrInputStream.java @@ -16,14 +16,14 @@ package android.media; -import java.io.InputStream; -import java.io.IOException; -import java.nio.ByteBuffer; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.MediaCodec.BufferInfo; import android.util.Log; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + /** * DO NOT USE diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java index 8ac26553bab4..c3dc118fec7e 100644 --- a/media/java/android/media/AsyncPlayer.java +++ b/media/java/android/media/AsyncPlayer.java @@ -17,9 +17,8 @@ package android.media; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.media.PlayerBase; import android.net.Uri; import android.os.PowerManager; import android.os.SystemClock; diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 820d82dd3bd1..bb874045817e 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.audiopolicy.AudioProductStrategy; import android.os.Build; import android.os.Bundle; diff --git a/media/java/android/media/AudioDeviceAddress.aidl b/media/java/android/media/AudioDeviceAddress.aidl new file mode 100644 index 000000000000..6a1a7f79247c --- /dev/null +++ b/media/java/android/media/AudioDeviceAddress.aidl @@ -0,0 +1,18 @@ +/* Copyright 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.media; + +parcelable AudioDeviceAddress; diff --git a/media/java/android/media/AudioDeviceAddress.java b/media/java/android/media/AudioDeviceAddress.java new file mode 100644 index 000000000000..415e77dc4049 --- /dev/null +++ b/media/java/android/media/AudioDeviceAddress.java @@ -0,0 +1,181 @@ +/* + * 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.media; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * @hide + * Class to represent device type (speaker, headset...), address and role (input, output) + * of an audio device. + * <p>Unlike {@link AudioDeviceInfo}, the device + * doesn't need to be connected to be uniquely identified, it can + * for instance represent a specific A2DP headset even after a + * disconnection, whereas the corresponding <code>AudioDeviceInfo</code> + * would then be invalid. + * <p>While creating / obtaining an instance is not protected by a + * permission, APIs using one rely on MODIFY_AUDIO_ROUTING. + */ +@SystemApi +public final class AudioDeviceAddress implements Parcelable { + + /** + * A role identifying input devices, such as microphones. + */ + public static final int ROLE_INPUT = AudioPort.ROLE_SOURCE; + /** + * A role identifying output devices, such as speakers or headphones. + */ + public static final int ROLE_OUTPUT = AudioPort.ROLE_SINK; + + /** @hide */ + @IntDef(flag = false, prefix = "ROLE_", value = { + ROLE_INPUT, ROLE_OUTPUT } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface Role {} + + /** + * The audio device type, as defined in {@link AudioDeviceInfo} + */ + private final @AudioDeviceInfo.AudioDeviceType int mType; + /** + * The unique address of the device. Some devices don't have addresses, only an empty string. + */ + private final @NonNull String mAddress; + + /** + * Is input or output device + */ + private final @Role int mRole; + + /** + * Constructor from a valid {@link AudioDeviceInfo} + * @param deviceInfo the connected audio device from which to obtain the device-identifying + * type and address. + */ + public AudioDeviceAddress(@NonNull AudioDeviceInfo deviceInfo) { + Objects.requireNonNull(deviceInfo); + mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT; + mType = deviceInfo.getType(); + mAddress = deviceInfo.getAddress(); + } + + public AudioDeviceAddress(@Role int role, @AudioDeviceInfo.AudioDeviceType int type, + @NonNull String address) { + Objects.requireNonNull(address); + if (role != ROLE_OUTPUT && role != ROLE_INPUT) { + throw new IllegalArgumentException("Invalid role " + role); + } + if (role == ROLE_OUTPUT && !AudioDeviceInfo.isValidAudioDeviceTypeOut(type)) { + throw new IllegalArgumentException("Invalid output device type " + type); + } + if (role == ROLE_INPUT && !AudioDeviceInfo.isValidAudioDeviceTypeIn(type)) { + throw new IllegalArgumentException("Invalid input device type " + type); + } + + mRole = role; + mType = type; + mAddress = address; + } + + public @Role int getRole() { + return mRole; + } + + public @AudioDeviceInfo.AudioDeviceType int getType() { + return mType; + } + + public @NonNull String getAddress() { + return mAddress; + } + + @Override + public int hashCode() { + return Objects.hash(mRole, mType, mAddress); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AudioDeviceAddress that = (AudioDeviceAddress) o; + return ((mRole == that.mRole) + && (mType == that.mType) + && mAddress.equals(that.mAddress)); + } + + /** @hide */ + public static String roleToString(@Role int role) { + return (role == ROLE_OUTPUT ? "output" : "input"); + } + + @Override + public String toString() { + return new String("AudioDeviceAddress:" + + " role:" + roleToString(mRole) + + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName( + AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType)) + : AudioSystem.getInputDeviceName( + AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType))) + + " addr:" + mAddress); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mRole); + dest.writeInt(mType); + dest.writeString(mAddress); + } + + private AudioDeviceAddress(@NonNull Parcel in) { + mRole = in.readInt(); + mType = in.readInt(); + mAddress = in.readString(); + } + + public static final @NonNull Parcelable.Creator<AudioDeviceAddress> CREATOR = + new Parcelable.Creator<AudioDeviceAddress>() { + /** + * Rebuilds an AudioDeviceAddress previously stored with writeToParcel(). + * @param p Parcel object to read the AudioDeviceAddress from + * @return a new AudioDeviceAddress created from the data in the parcel + */ + public AudioDeviceAddress createFromParcel(Parcel p) { + return new AudioDeviceAddress(p); + } + + public AudioDeviceAddress[] newArray(int size) { + return new AudioDeviceAddress[size]; + } + }; +} diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index ca895fcdfc4a..a39bc51acb24 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -149,6 +149,55 @@ public final class AudioDeviceInfo { TYPE_AUX_LINE, TYPE_IP, TYPE_BUS, + TYPE_HEARING_AID, + TYPE_BUILTIN_MIC, + TYPE_FM_TUNER, + TYPE_TV_TUNER } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface AudioDeviceType {} /** @hide */ + @IntDef(flag = false, prefix = "TYPE", value = { + TYPE_BUILTIN_MIC, + TYPE_BLUETOOTH_SCO, + TYPE_BLUETOOTH_A2DP, + TYPE_WIRED_HEADSET, + TYPE_HDMI, + TYPE_TELEPHONY, + TYPE_DOCK, + TYPE_USB_ACCESSORY, + TYPE_USB_DEVICE, + TYPE_USB_HEADSET, + TYPE_FM_TUNER, + TYPE_TV_TUNER, + TYPE_LINE_ANALOG, + TYPE_LINE_DIGITAL, + TYPE_IP, + TYPE_BUS } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface AudioDeviceTypeIn {} + + /** @hide */ + @IntDef(flag = false, prefix = "TYPE", value = { + TYPE_BUILTIN_EARPIECE, + TYPE_BUILTIN_SPEAKER, + TYPE_WIRED_HEADSET, + TYPE_WIRED_HEADPHONES, + TYPE_BLUETOOTH_SCO, + TYPE_BLUETOOTH_A2DP, + TYPE_HDMI, + TYPE_DOCK, + TYPE_USB_ACCESSORY, + TYPE_USB_DEVICE, + TYPE_USB_HEADSET, + TYPE_TELEPHONY, + TYPE_LINE_ANALOG, + TYPE_HDMI_ARC, + TYPE_LINE_DIGITAL, + TYPE_FM, + TYPE_AUX_LINE, + TYPE_IP, + TYPE_BUS, TYPE_HEARING_AID } ) @Retention(RetentionPolicy.SOURCE) @@ -183,6 +232,31 @@ public final class AudioDeviceInfo { } } + /** @hide */ + /*package*/ static boolean isValidAudioDeviceTypeIn(int type) { + switch (type) { + case TYPE_BUILTIN_MIC: + case TYPE_BLUETOOTH_SCO: + case TYPE_BLUETOOTH_A2DP: + case TYPE_WIRED_HEADSET: + case TYPE_HDMI: + case TYPE_TELEPHONY: + case TYPE_DOCK: + case TYPE_USB_ACCESSORY: + case TYPE_USB_DEVICE: + case TYPE_USB_HEADSET: + case TYPE_FM_TUNER: + case TYPE_TV_TUNER: + case TYPE_LINE_ANALOG: + case TYPE_LINE_DIGITAL: + case TYPE_IP: + case TYPE_BUS: + return true; + default: + return false; + } + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index 62b18cbafcb1..51909db11a09 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -16,8 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; -import android.media.AudioSystem; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioDevicePort is a specialized type of AudioPort diff --git a/media/java/android/media/AudioDevicePortConfig.java b/media/java/android/media/AudioDevicePortConfig.java index 0c647ea85c60..51b8037b82f8 100644 --- a/media/java/android/media/AudioDevicePortConfig.java +++ b/media/java/android/media/AudioDevicePortConfig.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An AudioDevicePortConfig describes a possible configuration of an output or input device diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index e55585ada6eb..7ff15df2d65e 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/media/java/android/media/AudioGain.java b/media/java/android/media/AudioGain.java index dd129a26ee59..cae1b59d46a7 100644 --- a/media/java/android/media/AudioGain.java +++ b/media/java/android/media/AudioGain.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioGain describes a gain controller. Gain controllers are exposed by diff --git a/media/java/android/media/AudioGainConfig.java b/media/java/android/media/AudioGainConfig.java index f5ebef85d302..dfefa8621ef8 100644 --- a/media/java/android/media/AudioGainConfig.java +++ b/media/java/android/media/AudioGainConfig.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioGainConfig is used by APIs setting or getting values on a given gain diff --git a/media/java/android/media/AudioHandle.java b/media/java/android/media/AudioHandle.java index 24f81f918af2..8fc834f8d0a9 100644 --- a/media/java/android/media/AudioHandle.java +++ b/media/java/android/media/AudioHandle.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioHandle is used by the audio framework implementation to diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index f797da70e7d1..32eec0054d9b 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -27,12 +27,12 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java index c4a5c4d86a41..33d603f0b9da 100644 --- a/media/java/android/media/AudioMixPort.java +++ b/media/java/android/media/AudioMixPort.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioMixPort is a specialized type of AudioPort diff --git a/media/java/android/media/AudioMixPortConfig.java b/media/java/android/media/AudioMixPortConfig.java index 315e46b725ad..9d8120624a45 100644 --- a/media/java/android/media/AudioMixPortConfig.java +++ b/media/java/android/media/AudioMixPortConfig.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An AudioMixPortConfig describes a possible configuration of an output or input mixer. diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java index d1f800694f50..e5107d4e3309 100644 --- a/media/java/android/media/AudioPatch.java +++ b/media/java/android/media/AudioPatch.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java index 83eb240be743..7c3ca24e1c9a 100644 --- a/media/java/android/media/AudioPort.java +++ b/media/java/android/media/AudioPort.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An audio port is a node of the audio framework or hardware that can be connected to or diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java index ac19bb167905..16fb5b80eb3e 100644 --- a/media/java/android/media/AudioPortConfig.java +++ b/media/java/android/media/AudioPortConfig.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An AudioPortConfig contains a possible configuration of an audio port chosen diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java index 6d9d6265f5e7..14249cbe8945 100644 --- a/media/java/android/media/AudioPortEventHandler.java +++ b/media/java/android/media/AudioPortEventHandler.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index ce9b07dd0c0e..306999cef7e7 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -23,8 +23,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.media.MediaRecorder.Source; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java index 874a215e4975..5f32c0f3f4a8 100644 --- a/media/java/android/media/AudioRecordingConfiguration.java +++ b/media/java/android/media/AudioRecordingConfiguration.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.audiofx.AudioEffect; import android.os.Parcel; import android.os.Parcelable; diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 1033e56776b9..1ad61983904c 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -19,8 +19,8 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothCodecConfig; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.media.audiofx.AudioEffect; diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 7cd09de41346..0ced68ef8695 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -23,7 +23,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java index 963b1d1504e2..e4bab7466a70 100644 --- a/media/java/android/media/CamcorderProfile.java +++ b/media/java/android/media/CamcorderProfile.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.os.Build; diff --git a/media/java/android/media/DecoderCapabilities.java b/media/java/android/media/DecoderCapabilities.java index df5e918ba8d5..ebfc63bd9bcd 100644 --- a/media/java/android/media/DecoderCapabilities.java +++ b/media/java/android/media/DecoderCapabilities.java @@ -16,9 +16,10 @@ package android.media; -import android.annotation.UnsupportedAppUsage; -import java.util.List; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; +import java.util.List; /** * {@hide} diff --git a/media/java/android/media/EncoderCapabilities.java b/media/java/android/media/EncoderCapabilities.java index c09c5fae1213..67ce0f7cc0b9 100644 --- a/media/java/android/media/EncoderCapabilities.java +++ b/media/java/android/media/EncoderCapabilities.java @@ -16,9 +16,10 @@ package android.media; -import android.annotation.UnsupportedAppUsage; -import java.util.List; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; +import java.util.List; /** * The EncoderCapabilities class is used to retrieve the diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 5645ba5d7dac..b41792710cbf 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -20,7 +20,7 @@ import android.annotation.CurrentTimeMillisLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java index 70a343f4de01..b5acbd457db0 100644 --- a/media/java/android/media/Image.java +++ b/media/java/android/media/Image.java @@ -16,14 +16,13 @@ package android.media; -import java.nio.ByteBuffer; -import java.lang.AutoCloseable; - import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.hardware.HardwareBuffer; +import java.nio.ByteBuffer; + /** * <p>A single complete image buffer to use with a media source such as a * {@link MediaCodec} or a diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java index e85b3ff99104..84ee09b35b81 100644 --- a/media/java/android/media/JetPlayer.java +++ b/media/java/android/media/JetPlayer.java @@ -17,7 +17,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.os.Handler; import android.os.Looper; diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index c9d79784004c..e702f19903d0 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.ImageFormat; import android.graphics.Rect; import android.graphics.SurfaceTexture; diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index f304f7cc5981..f3752d56ea0f 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -22,7 +22,7 @@ import static android.media.Utils.sortDistinctRanges; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.SystemProperties; import android.util.Log; diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index a08aec3ed20c..ea9a373a19f2 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -21,17 +21,17 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; -import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; -import android.os.Message; import android.os.Parcel; import android.os.PersistableBundle; import android.util.Log; + import dalvik.system.CloseGuard; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index c4eb0310f292..9908e042c6a4 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -20,7 +20,7 @@ import static android.content.ContentResolver.MIME_TYPE_DEFAULT; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.mtp.MtpConstants; import libcore.content.type.MimeMap; diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 8b667f772867..841799a58aa4 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java index 8ee929e77899..a17ff825e21b 100644 --- a/media/java/android/media/MediaHTTPConnection.java +++ b/media/java/android/media/MediaHTTPConnection.java @@ -18,13 +18,14 @@ package android.media; import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.NetworkUtils; import android.os.IBinder; import android.os.StrictMode; import android.util.Log; import com.android.internal.annotations.GuardedBy; + import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; diff --git a/media/java/android/media/MediaHTTPService.java b/media/java/android/media/MediaHTTPService.java index 97a0df799101..3008067daefb 100644 --- a/media/java/android/media/MediaHTTPService.java +++ b/media/java/android/media/MediaHTTPService.java @@ -17,7 +17,7 @@ package android.media; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.util.Log; diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java index 0749f58e460d..ca7a01cb990d 100644 --- a/media/java/android/media/MediaInserter.java +++ b/media/java/android/media/MediaInserter.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProviderClient; import android.content.ContentValues; import android.net.Uri; diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java index 8512dbe8d224..a23191f36efc 100644 --- a/media/java/android/media/MediaMetadata.java +++ b/media/java/android/media/MediaMetadata.java @@ -17,7 +17,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.StringDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index c43b78cf4fc7..a21a630e200a 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java index 0fb392bfc0fe..14a48d72f9bb 100644 --- a/media/java/android/media/MediaMuxer.java +++ b/media/java/android/media/MediaMuxer.java @@ -18,8 +18,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; -import android.media.MediaCodec; +import android.compat.annotation.UnsupportedAppUsage; import android.media.MediaCodec.BufferInfo; import dalvik.system.CloseGuard; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 353e58e98efa..6b953ae932f0 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -19,8 +19,8 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 63b22df12953..c957a883be1a 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -23,8 +23,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.Camera; import android.os.Build; import android.os.Handler; diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index d72231f40dcf..9837e1cc62b3 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -22,8 +22,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 771628cf7b1e..317502d760a8 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentUris; diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java index 792a2ba678fd..ef17073654a6 100644 --- a/media/java/android/media/Metadata.java +++ b/media/java/android/media/Metadata.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.util.Log; import android.util.MathUtils; diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java index f805975d53b0..876628fefff4 100644 --- a/media/java/android/media/MicrophoneInfo.java +++ b/media/java/android/media/MicrophoneInfo.java @@ -18,7 +18,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Pair; import java.lang.annotation.Retention; diff --git a/media/java/android/media/PlaybackParams.java b/media/java/android/media/PlaybackParams.java index b4325b6ea53d..f24f831d0333 100644 --- a/media/java/android/media/PlaybackParams.java +++ b/media/java/android/media/PlaybackParams.java @@ -18,7 +18,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index 325420b06122..c5fd3c30236d 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -16,8 +16,8 @@ package android.media; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.graphics.Bitmap; diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java index f70963a982e4..9e48f1e05391 100644 --- a/media/java/android/media/RemoteController.java +++ b/media/java/android/media/RemoteController.java @@ -16,8 +16,8 @@ package android.media; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.graphics.Bitmap; diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java index 2be206f2f462..e529af9da935 100644 --- a/media/java/android/media/RemoteDisplay.java +++ b/media/java/android/media/RemoteDisplay.java @@ -16,12 +16,12 @@ package android.media; -import dalvik.system.CloseGuard; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.view.Surface; +import dalvik.system.CloseGuard; + /** * Listens for Wifi remote display connections managed by the media server. * diff --git a/media/java/android/media/RemoteDisplayState.java b/media/java/android/media/RemoteDisplayState.java index 2f4ace0c8fdd..fed361a960e6 100644 --- a/media/java/android/media/RemoteDisplayState.java +++ b/media/java/android/media/RemoteDisplayState.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index eb680c8377f4..d35bc4176cb3 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -17,7 +17,7 @@ package android.media; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index 435d8d766149..6fd47c42bcba 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -22,9 +22,9 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; import android.app.Activity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentUris; diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java index 1a241af7345d..48657a6c810f 100644 --- a/media/java/android/media/SubtitleController.java +++ b/media/java/android/media/SubtitleController.java @@ -16,10 +16,7 @@ package android.media; -import java.util.Locale; -import java.util.Vector; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.MediaPlayer.TrackInfo; import android.media.SubtitleTrack.RenderingWidget; @@ -28,6 +25,9 @@ import android.os.Looper; import android.os.Message; import android.view.accessibility.CaptioningManager; +import java.util.Locale; +import java.util.Vector; + /** * The subtitle controller provides the architecture to display subtitles for a * media source. It allows specifying which tracks to display, on which anchor diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java index 0705d97a9edf..10669f466fe5 100644 --- a/media/java/android/media/SubtitleTrack.java +++ b/media/java/android/media/SubtitleTrack.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.media.MediaPlayer.TrackInfo; import android.os.Handler; diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java index 534d63b4cca0..cbdf9adfd0e1 100644 --- a/media/java/android/media/ThumbnailUtils.java +++ b/media/java/android/media/ThumbnailUtils.java @@ -24,7 +24,7 @@ import static android.os.Environment.MEDIA_UNKNOWN; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; diff --git a/media/java/android/media/TimedText.java b/media/java/android/media/TimedText.java index d8cdf9c12e09..120642a8e7cb 100644 --- a/media/java/android/media/TimedText.java +++ b/media/java/android/media/TimedText.java @@ -16,14 +16,15 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.os.Parcel; import android.util.Log; + +import java.util.ArrayList; import java.util.HashMap; -import java.util.Set; import java.util.List; -import java.util.ArrayList; +import java.util.Set; /** * Class to hold the timed text's metadata, including: diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java index c6d5ba3f9953..cc114a9092e1 100644 --- a/media/java/android/media/ToneGenerator.java +++ b/media/java/android/media/ToneGenerator.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java index 34154ce93a8c..e5782642f4eb 100644 --- a/media/java/android/media/TtmlRenderer.java +++ b/media/java/android/media/TtmlRenderer.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; @@ -27,6 +27,10 @@ import android.view.accessibility.CaptioningManager; import android.widget.LinearLayout; import android.widget.TextView; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; @@ -37,10 +41,6 @@ import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - /** @hide */ public class TtmlRenderer extends SubtitleController.Renderer { private final Context mContext; diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java index 663d564af23e..99dfe1e8e32f 100644 --- a/media/java/android/media/VolumeShaper.java +++ b/media/java/android/media/VolumeShaper.java @@ -19,13 +19,12 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.AutoCloseable; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Objects; diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java index 36458d7e1746..bc1429499e70 100644 --- a/media/java/android/media/WebVttRenderer.java +++ b/media/java/android/media/WebVttRenderer.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.text.Layout.Alignment; import android.text.SpannableStringBuilder; diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 5b4bbce91784..cad5aa6aaa3c 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -16,11 +16,18 @@ package android.media.audiofx; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; +import android.media.AudioDeviceAddress; +import android.media.AudioDeviceInfo; +import android.media.AudioSystem; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -448,12 +455,46 @@ public class AudioEffect { public AudioEffect(UUID type, UUID uuid, int priority, int audioSession) throws IllegalArgumentException, UnsupportedOperationException, RuntimeException { + this(type, uuid, priority, audioSession, null); + } + + /** + * Constructs an AudioEffect attached to a particular audio device. + * The device does not have to be attached when the effect is created. The effect will only + * be applied when the device is actually selected for playback or capture. + * @param uuid unique identifier of a particular effect implementation. + * @param device the device the effect must be attached to. + * + * @throws java.lang.IllegalArgumentException + * @throws java.lang.UnsupportedOperationException + * @throws java.lang.RuntimeException + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + public AudioEffect(@NonNull UUID uuid, @NonNull AudioDeviceAddress device) { + this(EFFECT_TYPE_NULL, Objects.requireNonNull(uuid), 0, -2, Objects.requireNonNull(device)); + } + + private AudioEffect(UUID type, UUID uuid, int priority, + int audioSession, @Nullable AudioDeviceAddress device) + throws IllegalArgumentException, UnsupportedOperationException, + RuntimeException { int[] id = new int[1]; Descriptor[] desc = new Descriptor[1]; + + int deviceType = AudioSystem.DEVICE_NONE; + String deviceAddress = ""; + if (device != null) { + deviceType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()); + deviceAddress = device.getAddress(); + } + // native initialization int initResult = native_setup(new WeakReference<AudioEffect>(this), - type.toString(), uuid.toString(), priority, audioSession, id, - desc, ActivityThread.currentOpPackageName()); + type.toString(), uuid.toString(), priority, audioSession, + deviceType, deviceAddress, + id, desc, ActivityThread.currentOpPackageName()); if (initResult != SUCCESS && initResult != ALREADY_EXISTS) { Log.e(TAG, "Error code " + initResult + " when initializing AudioEffect."); @@ -1293,7 +1334,8 @@ public class AudioEffect { private static native final void native_init(); private native final int native_setup(Object audioeffect_this, String type, - String uuid, int priority, int audioSession, int[] id, Object[] desc, + String uuid, int priority, int audioSession, + int deviceType, String deviceAddress, int[] id, Object[] desc, String opPackageName); private native final void native_finalize(); diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index 89a509f64a1b..392e8fe7543f 100644 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -16,8 +16,8 @@ package android.media.audiofx; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; import android.os.Message; diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java index a82c78fad271..dd9877a9c706 100644 --- a/media/java/android/media/audiopolicy/AudioMix.java +++ b/media/java/android/media/audiopolicy/AudioMix.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioDeviceInfo; import android.media.AudioFormat; import android.media.AudioSystem; diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java index c4afd95be9ac..8c204d222cd4 100644 --- a/media/java/android/media/audiopolicy/AudioMixingRule.java +++ b/media/java/android/media/audiopolicy/AudioMixingRule.java @@ -19,7 +19,7 @@ package android.media.audiopolicy; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioAttributes; import android.os.Parcel; import android.util.Log; diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 1fc4f7d59ca5..a856653e8bc9 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -18,8 +18,8 @@ package android.media.session; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index e11715ff7299..5db4e8c1e3f7 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -19,9 +19,9 @@ package android.media.session; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java index 123c4f75d5b6..0d506f0eb52c 100644 --- a/media/java/android/media/session/MediaSessionLegacyHelper.java +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -16,9 +16,9 @@ package android.media.session; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -26,7 +26,6 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; -import android.media.AudioManager; import android.media.MediaMetadata; import android.media.MediaMetadataEditor; import android.media.MediaMetadataRetriever; diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index a89dc5f1d2af..aff725734ee1 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -22,7 +22,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ParceledListSlice; diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java index 56e5566df29c..77596a5de815 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java +++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java @@ -22,7 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java index ada77c53bb34..3f0aec63283c 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerManager.java +++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java @@ -23,7 +23,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.hardware.soundtrigger.SoundTrigger; diff --git a/media/java/android/media/tv/DvbDeviceInfo.java b/media/java/android/media/tv/DvbDeviceInfo.java index a574fe18fb63..96c852812a74 100644 --- a/media/java/android/media/tv/DvbDeviceInfo.java +++ b/media/java/android/media/tv/DvbDeviceInfo.java @@ -16,6 +16,8 @@ package android.media.tv; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -26,10 +28,11 @@ import android.util.Log; * * @hide */ +@SystemApi public final class DvbDeviceInfo implements Parcelable { static final String TAG = "DvbDeviceInfo"; - public static final @android.annotation.NonNull Parcelable.Creator<DvbDeviceInfo> CREATOR = + public static final @NonNull Parcelable.Creator<DvbDeviceInfo> CREATOR = new Parcelable.Creator<DvbDeviceInfo>() { @Override public DvbDeviceInfo createFromParcel(Parcel source) { @@ -86,7 +89,7 @@ public final class DvbDeviceInfo implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mAdapterId); dest.writeInt(mDeviceId); } diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 1b9cac0c8c99..377b2bc19c6b 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.StringRes; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index d22a29893540..854ea43f17c3 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -103,6 +103,12 @@ public final class TvInputManager { /** @hide */ @Retention(RetentionPolicy.SOURCE) + @IntDef({DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_FRONTEND}) + public @interface DvbDeviceType {} + + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING, VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING, VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}) @@ -1663,6 +1669,9 @@ public final class TvInputManager { * @return the list of {@link DvbDeviceInfo} objects representing available DVB devices. * @hide */ + @SystemApi + @RequiresPermission(android.Manifest.permission.DVB_DEVICE) + @NonNull public List<DvbDeviceInfo> getDvbDeviceList() { try { return mService.getDvbDeviceList(); @@ -1676,19 +1685,24 @@ public final class TvInputManager { * {@link DvbDeviceInfo} * * @param info A {@link DvbDeviceInfo} to open a DVB device. - * @param device A DVB device. The DVB device can be {@link #DVB_DEVICE_DEMUX}, + * @param deviceType A DVB device type. The type can be {@link #DVB_DEVICE_DEMUX}, * {@link #DVB_DEVICE_DVR} or {@link #DVB_DEVICE_FRONTEND}. * @return a {@link ParcelFileDescriptor} of a specified DVB device for a given - * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo} was invalid - * or the specified DVB device was busy with a previous request. + * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo} + * failed to open. + * @throws IllegalArgumentException if {@code deviceType} is invalid or the device is not found. * @hide */ - public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info, int device) { + @SystemApi + @RequiresPermission(android.Manifest.permission.DVB_DEVICE) + @Nullable + public ParcelFileDescriptor openDvbDevice(@NonNull DvbDeviceInfo info, + @DvbDeviceType int deviceType) { try { - if (DVB_DEVICE_START > device || DVB_DEVICE_END < device) { - throw new IllegalArgumentException("Invalid DVB device: " + device); + if (DVB_DEVICE_START > deviceType || DVB_DEVICE_END < deviceType) { + throw new IllegalArgumentException("Invalid DVB device: " + deviceType); } - return mService.openDvbDevice(info, device); + return mService.openDvbDevice(info, deviceType); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 5c11ed9bb7b4..7fbb3376d5fb 100755 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -22,9 +22,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java index ea00d6eff12e..4318a0ae7d06 100644 --- a/media/java/android/media/tv/TvTrackInfo.java +++ b/media/java/android/media/tv/TvTrackInfo.java @@ -61,6 +61,9 @@ public final class TvTrackInfo implements Parcelable { private final boolean mEncrypted; private final int mAudioChannelCount; private final int mAudioSampleRate; + private final boolean mAudioDescription; + private final boolean mHardOfHearing; + private final boolean mSpokenSubtitle; private final int mVideoWidth; private final int mVideoHeight; private final float mVideoFrameRate; @@ -70,9 +73,10 @@ public final class TvTrackInfo implements Parcelable { private final Bundle mExtra; private TvTrackInfo(int type, String id, String language, CharSequence description, - boolean encrypted, int audioChannelCount, int audioSampleRate, int videoWidth, - int videoHeight, float videoFrameRate, float videoPixelAspectRatio, - byte videoActiveFormatDescription, Bundle extra) { + boolean encrypted, int audioChannelCount, int audioSampleRate, boolean audioDescription, + boolean hardOfHearing, boolean spokenSubtitle, int videoWidth, int videoHeight, + float videoFrameRate, float videoPixelAspectRatio, byte videoActiveFormatDescription, + Bundle extra) { mType = type; mId = id; mLanguage = language; @@ -80,6 +84,9 @@ public final class TvTrackInfo implements Parcelable { mEncrypted = encrypted; mAudioChannelCount = audioChannelCount; mAudioSampleRate = audioSampleRate; + mAudioDescription = audioDescription; + mHardOfHearing = hardOfHearing; + mSpokenSubtitle = spokenSubtitle; mVideoWidth = videoWidth; mVideoHeight = videoHeight; mVideoFrameRate = videoFrameRate; @@ -96,6 +103,9 @@ public final class TvTrackInfo implements Parcelable { mEncrypted = in.readInt() != 0; mAudioChannelCount = in.readInt(); mAudioSampleRate = in.readInt(); + mAudioDescription = in.readInt() != 0; + mHardOfHearing = in.readInt() != 0; + mSpokenSubtitle = in.readInt() != 0; mVideoWidth = in.readInt(); mVideoHeight = in.readInt(); mVideoFrameRate = in.readFloat(); @@ -172,6 +182,56 @@ public final class TvTrackInfo implements Parcelable { } /** + * Returns {@code true} if the track is an audio description intended for people with visual + * impairment, {@code false} otherwise. Valid only for {@link #TYPE_AUDIO} tracks. + * + * <p>For example of broadcast, audio description information may be referred to broadcast + * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio Language + * Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN 300 468). + * + * @throws IllegalStateException if not called on an audio track + */ + public boolean isAudioDescription() { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + return mAudioDescription; + } + + /** + * Returns {@code true} if the track is intended for people with hearing impairment, {@code + * false} otherwise. Valid only for {@link #TYPE_AUDIO} and {@link #TYPE_SUBTITLE} tracks. + * + * <p>For example of broadcast, hard of hearing information may be referred to broadcast + * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio Language + * Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN 300 468). + * + * @throws IllegalStateException if not called on an audio track or a subtitle track + */ + public boolean isHardOfHearing() { + if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) { + throw new IllegalStateException("Not an audio or a subtitle track"); + } + return mHardOfHearing; + } + + /** + * Returns {@code true} if the track is a spoken subtitle for people with visual impairment, + * {@code false} otherwise. Valid only for {@link #TYPE_AUDIO} tracks. + * + * <p>For example of broadcast, spoken subtitle information may be referred to broadcast + * standard (e.g. Supplementary Audio Language Descriptor of ETSI EN 300 468). + * + * @throws IllegalStateException if not called on an audio track + */ + public boolean isSpokenSubtitle() { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + return mSpokenSubtitle; + } + + /** * Returns the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO} * tracks. * @@ -266,6 +326,9 @@ public final class TvTrackInfo implements Parcelable { dest.writeInt(mEncrypted ? 1 : 0); dest.writeInt(mAudioChannelCount); dest.writeInt(mAudioSampleRate); + dest.writeInt(mAudioDescription ? 1 : 0); + dest.writeInt(mHardOfHearing ? 1 : 0); + dest.writeInt(mSpokenSubtitle ? 1 : 0); dest.writeInt(mVideoWidth); dest.writeInt(mVideoHeight); dest.writeFloat(mVideoFrameRate); @@ -289,6 +352,7 @@ public final class TvTrackInfo implements Parcelable { if (!TextUtils.equals(mId, obj.mId) || mType != obj.mType || !TextUtils.equals(mLanguage, obj.mLanguage) || !TextUtils.equals(mDescription, obj.mDescription) + || mEncrypted != obj.mEncrypted || !Objects.equals(mExtra, obj.mExtra)) { return false; } @@ -296,7 +360,10 @@ public final class TvTrackInfo implements Parcelable { switch (mType) { case TYPE_AUDIO: return mAudioChannelCount == obj.mAudioChannelCount - && mAudioSampleRate == obj.mAudioSampleRate; + && mAudioSampleRate == obj.mAudioSampleRate + && mAudioDescription == obj.mAudioDescription + && mHardOfHearing == obj.mHardOfHearing + && mSpokenSubtitle == obj.mSpokenSubtitle; case TYPE_VIDEO: return mVideoWidth == obj.mVideoWidth @@ -304,6 +371,9 @@ public final class TvTrackInfo implements Parcelable { && mVideoFrameRate == obj.mVideoFrameRate && mVideoPixelAspectRatio == obj.mVideoPixelAspectRatio && mVideoActiveFormatDescription == obj.mVideoActiveFormatDescription; + + case TYPE_SUBTITLE: + return mHardOfHearing == obj.mHardOfHearing; } return true; @@ -338,6 +408,9 @@ public final class TvTrackInfo implements Parcelable { private boolean mEncrypted; private int mAudioChannelCount; private int mAudioSampleRate; + private boolean mAudioDescription; + private boolean mHardOfHearing; + private boolean mSpokenSubtitle; private int mVideoWidth; private int mVideoHeight; private float mVideoFrameRate; @@ -430,6 +503,67 @@ public final class TvTrackInfo implements Parcelable { } /** + * Sets the audio description attribute of the audio. Valid only for {@link #TYPE_AUDIO} + * tracks. + * + * <p>For example of broadcast, audio description information may be referred to broadcast + * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio + * Language Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN + * 300 468). + * + * @param audioDescription The audio description attribute of the audio. + * @throws IllegalStateException if not called on an audio track + */ + @NonNull + public Builder setAudioDescription(boolean audioDescription) { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + mAudioDescription = audioDescription; + return this; + } + + /** + * Sets the hard of hearing attribute of the track. Valid only for {@link #TYPE_AUDIO} and + * {@link #TYPE_SUBTITLE} tracks. + * + * <p>For example of broadcast, hard of hearing information may be referred to broadcast + * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio + * Language Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN + * 300 468). + * + * @param hardOfHearing The hard of hearing attribute of the track. + * @throws IllegalStateException if not called on an audio track or a subtitle track + */ + @NonNull + public Builder setHardOfHearing(boolean hardOfHearing) { + if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) { + throw new IllegalStateException("Not an audio track or a subtitle track"); + } + mHardOfHearing = hardOfHearing; + return this; + } + + /** + * Sets the spoken subtitle attribute of the audio. Valid only for {@link #TYPE_AUDIO} + * tracks. + * + * <p>For example of broadcast, spoken subtitle information may be referred to broadcast + * standard (e.g. Supplementary Audio Language Descriptor of ETSI EN 300 468). + * + * @param spokenSubtitle The spoken subtitle attribute of the audio. + * @throws IllegalStateException if not called on an audio track + */ + @NonNull + public Builder setSpokenSubtitle(boolean spokenSubtitle) { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + mSpokenSubtitle = spokenSubtitle; + return this; + } + + /** * Sets the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO} * tracks. * @@ -531,8 +665,9 @@ public final class TvTrackInfo implements Parcelable { */ public TvTrackInfo build() { return new TvTrackInfo(mType, mId, mLanguage, mDescription, mEncrypted, - mAudioChannelCount, mAudioSampleRate, mVideoWidth, mVideoHeight, - mVideoFrameRate, mVideoPixelAspectRatio, mVideoActiveFormatDescription, mExtra); + mAudioChannelCount, mAudioSampleRate, mAudioDescription, mHardOfHearing, + mSpokenSubtitle, mVideoWidth, mVideoHeight, mVideoFrameRate, + mVideoPixelAspectRatio, mVideoActiveFormatDescription, mExtra); } } } diff --git a/media/java/android/mtp/MtpPropertyList.java b/media/java/android/mtp/MtpPropertyList.java index 557f099c25c1..53d838d84518 100644 --- a/media/java/android/mtp/MtpPropertyList.java +++ b/media/java/android/mtp/MtpPropertyList.java @@ -16,7 +16,8 @@ package android.mtp; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; import java.util.List; diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java index 65d0fef74b25..d385816c6f86 100644 --- a/media/java/android/mtp/MtpStorage.java +++ b/media/java/android/mtp/MtpStorage.java @@ -16,7 +16,7 @@ package android.mtp; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.storage.StorageVolume; import android.provider.MediaStore; diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index 86a1076af122..06adf30a8303 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -21,8 +21,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 8d420e2c5598..05aaa82f8ac8 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -743,8 +743,10 @@ status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const } status_t JMediaCodec::getMetrics(JNIEnv *, MediaAnalyticsItem * &reply) const { - - status_t status = mCodec->getMetrics(reply); + mediametrics_handle_t reply2 = MediaAnalyticsItem::convert(reply); + status_t status = mCodec->getMetrics(reply2); + // getMetrics() updates reply2, pass the converted update along to our caller. + reply = MediaAnalyticsItem::convert(reply2); return status; } @@ -1848,7 +1850,7 @@ android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz) } // get what we have for the metrics from the codec - MediaAnalyticsItem *item = NULL; + MediaAnalyticsItem *item = 0; status_t err = codec->getMetrics(env, item); if (err != OK) { @@ -1860,7 +1862,7 @@ android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz) // housekeeping delete item; - item = NULL; + item = 0; return mybundle; } diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp index 41ab6703a579..5ba5c0159275 100644 --- a/media/jni/audioeffect/Android.bp +++ b/media/jni/audioeffect/Android.bp @@ -17,6 +17,7 @@ cc_library_shared { "libnativehelper", "libaudioclient", "libaudioutils", + "libaudiofoundation", ], version_script: "exports.lds", diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index 747d4c01867e..007dd10aba1f 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -268,8 +268,9 @@ android_media_AudioEffect_native_init(JNIEnv *env) static jint android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, - jobjectArray javadesc, jstring opPackageName) + jstring type, jstring uuid, jint priority, jint sessionId, + jint deviceType, jstring deviceAddress, + jintArray jId, jobjectArray javadesc, jstring opPackageName) { ALOGV("android_media_AudioEffect_native_setup"); AudioEffectJniStorage* lpJniStorage = NULL; @@ -280,6 +281,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t const char *uuidStr = NULL; effect_descriptor_t desc; jobject jdesc; + AudioDeviceTypeAddr device; ScopedUtfChars opPackageNameStr(env, opPackageName); @@ -328,6 +330,12 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t goto setup_failure; } + if (deviceType != AUDIO_DEVICE_NONE) { + device.mType = deviceType; + ScopedUtfChars address(env, deviceAddress); + device.mAddress = address.c_str(); + } + // create the native AudioEffect object lpAudioEffect = new AudioEffect(typeStr, String16(opPackageNameStr.c_str()), @@ -336,7 +344,8 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t effectCallback, &lpJniStorage->mCallbackData, (audio_session_t) sessionId, - AUDIO_IO_HANDLE_NONE); + AUDIO_IO_HANDLE_NONE, + device); if (lpAudioEffect == 0) { ALOGE("Error creating AudioEffect"); goto setup_failure; @@ -757,7 +766,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _ // Dalvik VM type signatures static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Ljava/lang/String;)I", (void *)android_media_AudioEffect_native_setup}, {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize}, {"native_release", "()V", (void *)android_media_AudioEffect_native_release}, diff --git a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java index dfbf5d20e074..121443f56285 100644 --- a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java +++ b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java @@ -17,12 +17,11 @@ package android.media.effect; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.core.Filter; import android.filterfw.core.FilterFactory; import android.filterfw.core.FilterFunction; import android.filterfw.core.Frame; -import android.media.effect.EffectContext; /** * Effect subclass for effects based on a single Filter. Subclasses need only invoke the diff --git a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java index 52615bf09faa..3a7f1ed4f7ec 100644 --- a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java +++ b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java @@ -17,11 +17,11 @@ package android.filterfw; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.filterfw.core.AsyncRunner; -import android.filterfw.core.FilterGraph; import android.filterfw.core.FilterContext; +import android.filterfw.core.FilterGraph; import android.filterfw.core.FrameManager; import android.filterfw.core.GraphRunner; import android.filterfw.core.RoundRobinScheduler; diff --git a/media/mca/filterfw/java/android/filterfw/core/Filter.java b/media/mca/filterfw/java/android/filterfw/core/Filter.java index 4f56b923f6ed..a608ef5be3f4 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Filter.java +++ b/media/mca/filterfw/java/android/filterfw/core/Filter.java @@ -17,19 +17,15 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FilterContext; -import android.filterfw.core.FilterPort; -import android.filterfw.core.KeyValueMap; -import android.filterfw.io.TextGraphReader; -import android.filterfw.io.GraphIOException; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.format.ObjectFormat; +import android.filterfw.io.GraphIOException; +import android.filterfw.io.TextGraphReader; import android.util.Log; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; -import java.lang.Thread; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java index a19220ef85f8..6b0a2193dceb 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java +++ b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java @@ -17,11 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Filter; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameManager; -import android.filterfw.core.GLEnvironment; +import android.compat.annotation.UnsupportedAppUsage; import java.util.HashMap; import java.util.HashSet; diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java index e6ca11ffca3c..35a298fd6dfb 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java +++ b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java @@ -17,6 +17,11 @@ package android.filterfw.core; +import android.compat.annotation.UnsupportedAppUsage; +import android.filterpacks.base.FrameBranch; +import android.filterpacks.base.NullFilter; +import android.util.Log; + import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -25,14 +30,6 @@ import java.util.Map.Entry; import java.util.Set; import java.util.Stack; -import android.filterfw.core.FilterContext; -import android.filterfw.core.KeyValueMap; -import android.filterpacks.base.FrameBranch; -import android.filterpacks.base.NullFilter; - -import android.annotation.UnsupportedAppUsage; -import android.util.Log; - /** * @hide */ diff --git a/media/mca/filterfw/java/android/filterfw/core/Frame.java b/media/mca/filterfw/java/android/filterfw/core/Frame.java index e880783247a3..c4d935ae4873 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Frame.java +++ b/media/mca/filterfw/java/android/filterfw/core/Frame.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.FrameManager; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import java.nio.ByteBuffer; diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java index eb0ff0a32c3f..a87e9b9ffbcf 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java +++ b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.KeyValueMap; -import android.filterfw.core.MutableFrameFormat; +import android.compat.annotation.UnsupportedAppUsage; import java.util.Arrays; import java.util.Map.Entry; diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java index 85c8fcd9787d..e49aaf1d6fad 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java +++ b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java @@ -17,10 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.MutableFrameFormat; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java index e25d6a7d70ab..7e4e8a64a81f 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java +++ b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java @@ -17,13 +17,12 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.NativeAllocatorTag; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; +import android.media.MediaRecorder; import android.os.Looper; import android.util.Log; import android.view.Surface; -import android.media.MediaRecorder; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java index 9e3025fafb6e..1ccd7feaa7c3 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java +++ b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java @@ -17,15 +17,10 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.FrameManager; -import android.filterfw.core.NativeFrame; -import android.filterfw.core.StopWatchMap; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; -import android.opengl.GLES20; import android.graphics.Rect; +import android.opengl.GLES20; import java.nio.ByteBuffer; diff --git a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java index 250cfaaba9d4..b57e8bb7262e 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java +++ b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java @@ -17,7 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java index ae2ad99899f0..da00b1ffb180 100644 --- a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java +++ b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.KeyValueMap; +import android.compat.annotation.UnsupportedAppUsage; import java.util.Arrays; diff --git a/media/mca/filterfw/java/android/filterfw/core/Program.java b/media/mca/filterfw/java/android/filterfw/core/Program.java index 376c08554eb2..145388e4437e 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Program.java +++ b/media/mca/filterfw/java/android/filterfw/core/Program.java @@ -17,8 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java index f41636e7cf76..e043be0e27bd 100644 --- a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java +++ b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java @@ -17,12 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.NativeAllocatorTag; -import android.filterfw.core.Program; -import android.filterfw.core.StopWatchMap; -import android.filterfw.core.VertexFrame; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.geometry.Quad; import android.opengl.GLES20; diff --git a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java index ac087305287f..0e05092d0cdd 100644 --- a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java +++ b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java @@ -17,7 +17,7 @@ package android.filterfw.format; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.core.FrameFormat; import android.filterfw.core.MutableFrameFormat; import android.graphics.Bitmap; diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Point.java b/media/mca/filterfw/java/android/filterfw/geometry/Point.java index d7acf12dd1de..96d2d7b08b74 100644 --- a/media/mca/filterfw/java/android/filterfw/geometry/Point.java +++ b/media/mca/filterfw/java/android/filterfw/geometry/Point.java @@ -17,8 +17,7 @@ package android.filterfw.geometry; -import android.annotation.UnsupportedAppUsage; -import java.lang.Math; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java index 610e5b80399d..2b308a91576f 100644 --- a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java +++ b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java @@ -17,10 +17,8 @@ package android.filterfw.geometry; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.geometry.Point; +import android.compat.annotation.UnsupportedAppUsage; -import java.lang.Float; import java.util.Arrays; import java.util.Collections; import java.util.List; diff --git a/mms/OWNERS b/mms/OWNERS index ba00d5d75010..befc320b949c 100644 --- a/mms/OWNERS +++ b/mms/OWNERS @@ -12,3 +12,5 @@ satk@google.com shuoq@google.com refuhoo@google.com nazaninb@google.com +sarahchin@google.com +dbright@google.com
\ No newline at end of file diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java index 4bcf04691652..65542673a607 100644 --- a/mms/java/android/telephony/MmsManager.java +++ b/mms/java/android/telephony/MmsManager.java @@ -97,22 +97,4 @@ public class MmsManager { // Ignore it } } - - /** - * Get carrier-dependent configuration values. - * - * @param subId the subscription id - * @return bundle key/values pairs of configuration values - */ - public Bundle getCarrierConfigValues(int subId) { - try { - IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); - if (iMms != null) { - return iMms.getCarrierConfigValues(subId); - } - } catch (RemoteException ex) { - // ignore it - } - return null; - } } diff --git a/mms/java/com/android/internal/telephony/IMms.aidl b/mms/java/com/android/internal/telephony/IMms.aidl index fa5073ef1c7e..8be511186800 100644 --- a/mms/java/com/android/internal/telephony/IMms.aidl +++ b/mms/java/com/android/internal/telephony/IMms.aidl @@ -60,13 +60,6 @@ interface IMms { in PendingIntent downloadedIntent); /** - * Get carrier-dependent configuration values. - * - * @param subId the SIM id - */ - Bundle getCarrierConfigValues(int subId); - - /** * Import a text message into system's SMS store * * @param callingPkg the calling app's package name diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java index 728e6e18cc31..90b46fd5901a 100644 --- a/opengl/java/android/opengl/EGL14.java +++ b/opengl/java/android/opengl/EGL14.java @@ -18,11 +18,11 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; import android.view.Surface; -import android.view.SurfaceView; import android.view.SurfaceHolder; +import android.view.SurfaceView; /** * EGL 1.4 diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java index d66e7ac84a3b..e853e4447daa 100644 --- a/opengl/java/android/opengl/GLES20.java +++ b/opengl/java/android/opengl/GLES20.java @@ -19,7 +19,7 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** OpenGL ES 2.0 */ diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 8a3e6a0b0fd5..75131b0f6b9c 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -16,7 +16,7 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Trace; import android.util.AttributeSet; diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java index f94f69f0fd3f..b4ea0a6132a5 100644 --- a/opengl/java/com/google/android/gles_jni/EGLImpl.java +++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java @@ -16,13 +16,12 @@ package com.google.android.gles_jni; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; -import dalvik.annotation.compat.UnsupportedAppUsage; - import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java index 2a8d07f03148..3c808a6ada48 100644 --- a/opengl/java/com/google/android/gles_jni/GLImpl.java +++ b/opengl/java/com/google/android/gles_jni/GLImpl.java @@ -20,14 +20,13 @@ package com.google.android.gles_jni; import android.app.AppGlobals; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.os.Build; import android.os.UserHandle; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.nio.Buffer; import javax.microedition.khronos.opengles.GL10; diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java index 8a2517062d4d..ea571c7311a1 100644 --- a/opengl/java/javax/microedition/khronos/egl/EGL10.java +++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java @@ -16,8 +16,7 @@ package javax.microedition.khronos.egl; -import android.annotation.UnsupportedAppUsage; -import java.lang.String; +import android.compat.annotation.UnsupportedAppUsage; public interface EGL10 extends EGL { int EGL_SUCCESS = 0x3000; diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index 672879ae6e9d..68da999ae786 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -82,7 +82,7 @@ android_app { ], platform_apis: true, - product_specific: true, + system_ext_specific: true, certificate: "platform", privileged: true, diff --git a/packages/CarSystemUI/CleanSpec.mk b/packages/CarSystemUI/CleanSpec.mk new file mode 100644 index 000000000000..ceac67c55f09 --- /dev/null +++ b/packages/CarSystemUI/CleanSpec.mk @@ -0,0 +1,50 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/CarSystemUI) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/CarSystemUI) +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 9e49826f70c3..9ccb837cf613 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -56,6 +56,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.image.DynamicSystemClient; import android.os.image.DynamicSystemManager; +import android.text.TextUtils; import android.util.Log; import android.widget.Toast; @@ -74,6 +75,8 @@ public class DynamicSystemInstallationService extends Service // TODO (b/131866826): This is currently for test only. Will move this to System API. static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED"; + static final String KEY_DSU_SLOT = "KEY_DSU_SLOT"; + static final String DEFAULT_DSU_SLOT = "dsu"; /* * Intent actions @@ -244,10 +247,15 @@ public class DynamicSystemInstallationService extends Service long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0); long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0); mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false); + String dsuSlot = intent.getStringExtra(KEY_DSU_SLOT); + if (TextUtils.isEmpty(dsuSlot)) { + dsuSlot = DEFAULT_DSU_SLOT; + } // TODO: better constructor or builder - mInstallTask = new InstallationAsyncTask( - url, systemSize, userdataSize, this, mDynSystem, this); + mInstallTask = + new InstallationAsyncTask( + url, dsuSlot, systemSize, userdataSize, this, mDynSystem, this); mInstallTask.execute(); @@ -262,10 +270,11 @@ public class DynamicSystemInstallationService extends Service return; } + stopForeground(true); mJustCancelledByUser = true; if (mInstallTask.cancel(false)) { - // Will cleanup and post status in onResult() + // Will stopSelf() in onResult() Log.d(TAG, "Cancel request filed successfully"); } else { Log.e(TAG, "Trying to cancel installation while it's already completed."); @@ -408,7 +417,9 @@ public class DynamicSystemInstallationService extends Service break; case STATUS_READY: - builder.setContentText(getString(R.string.notification_install_completed)); + String msgCompleted = getString(R.string.notification_install_completed); + builder.setContentText(msgCompleted) + .setStyle(new Notification.BigTextStyle().bigText(msgCompleted)); builder.addAction(new Notification.Action.Builder( null, getString(R.string.notification_action_discard), @@ -421,7 +432,9 @@ public class DynamicSystemInstallationService extends Service break; case STATUS_IN_USE: - builder.setContentText(getString(R.string.notification_dynsystem_in_use)); + String msgInUse = getString(R.string.notification_dynsystem_in_use); + builder.setContentText(msgInUse) + .setStyle(new Notification.BigTextStyle().bigText(msgInUse)); builder.addAction(new Notification.Action.Builder( null, getString(R.string.notification_action_uninstall), @@ -451,7 +464,49 @@ public class DynamicSystemInstallationService extends Service } private void postStatus(int status, int cause, Throwable detail) { - Log.d(TAG, "postStatus(): statusCode=" + status + ", causeCode=" + cause); + String statusString; + String causeString; + + switch (status) { + case STATUS_NOT_STARTED: + statusString = "NOT_STARTED"; + break; + case STATUS_IN_PROGRESS: + statusString = "IN_PROGRESS"; + break; + case STATUS_READY: + statusString = "READY"; + break; + case STATUS_IN_USE: + statusString = "IN_USE"; + break; + default: + statusString = "UNKNOWN"; + break; + } + + switch (cause) { + case CAUSE_INSTALL_COMPLETED: + causeString = "INSTALL_COMPLETED"; + break; + case CAUSE_INSTALL_CANCELLED: + causeString = "INSTALL_CANCELLED"; + break; + case CAUSE_ERROR_IO: + causeString = "ERROR_IO"; + break; + case CAUSE_ERROR_INVALID_URL: + causeString = "ERROR_INVALID_URL"; + break; + case CAUSE_ERROR_EXCEPTION: + causeString = "ERROR_EXCEPTION"; + break; + default: + causeString = "CAUSE_NOT_SPECIFIED"; + break; + } + + Log.d(TAG, "status=" + statusString + ", cause=" + causeString); boolean notifyOnNotificationBar = true; diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index b206a1fccba4..9aea0e713179 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -89,10 +89,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog interface ProgressListener { void onProgressUpdate(Progress progress); + void onResult(int resultCode, Throwable detail); } private final String mUrl; + private final String mDsuSlot; private final long mSystemSize; private final long mUserdataSize; private final Context mContext; @@ -106,9 +108,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog private InputStream mStream; private ZipFile mZipFile; - InstallationAsyncTask(String url, long systemSize, long userdataSize, Context context, - DynamicSystemManager dynSystem, ProgressListener listener) { + InstallationAsyncTask( + String url, + String dsuSlot, + long systemSize, + long userdataSize, + Context context, + DynamicSystemManager dynSystem, + ProgressListener listener) { mUrl = url; + mDsuSlot = dsuSlot; mSystemSize = systemSize; mUserdataSize = userdataSize; mContext = context; @@ -126,14 +135,17 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog verifyAndPrepare(); - mDynSystem.startInstallation(); + mDynSystem.startInstallation(mDsuSlot); installUserdata(); if (isCancelled()) { mDynSystem.remove(); return null; } - + if (mUrl == null) { + mDynSystem.finishInstallation(); + return null; + } installImages(); if (isCancelled()) { mDynSystem.remove(); @@ -194,6 +206,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } private void verifyAndPrepare() throws Exception { + if (mUrl == null) { + return; + } String extension = mUrl.substring(mUrl.lastIndexOf('.') + 1); if ("gz".equals(extension) || "gzip".equals(extension)) { diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java index 3b3933b7db10..e42ded74acd0 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java @@ -28,11 +28,9 @@ import android.os.image.DynamicSystemClient; import android.util.FeatureFlagUtils; import android.util.Log; - /** - * This Activity starts KeyguardManager and ask the user to confirm - * before any installation request. If the device is not protected by - * a password, it approves the request by default. + * This Activity starts KeyguardManager and ask the user to confirm before any installation request. + * If the device is not protected by a password, it approves the request by default. */ public class VerificationActivity extends Activity { @@ -88,11 +86,15 @@ public class VerificationActivity extends Activity { Uri url = callingIntent.getData(); Bundle extras = callingIntent.getExtras(); - sVerifiedUrl = url.toString(); + if (url != null) { + sVerifiedUrl = url.toString(); + } // start service Intent intent = new Intent(this, DynamicSystemInstallationService.class); - intent.setData(url); + if (url != null) { + intent.setData(url); + } intent.setAction(DynamicSystemClient.ACTION_START_INSTALL); intent.putExtras(extras); @@ -106,6 +108,7 @@ public class VerificationActivity extends Activity { } static boolean isVerified(String url) { + if (url == null) return true; return sVerifiedUrl != null && sVerifiedUrl.equals(url); } } diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml index 39c55fd1925c..413211d93fdc 100644 --- a/packages/SettingsLib/res/values/arrays.xml +++ b/packages/SettingsLib/res/values/arrays.xml @@ -132,6 +132,20 @@ <item>avrcp16</item> </string-array> + <!-- Titles for Bluetooth MAP Versions --> + <string-array name="bluetooth_map_versions"> + <item>MAP 1.2 (Default)</item> + <item>MAP 1.3</item> + <item>MAP 1.4</item> + </string-array> + + <!-- Values for Bluetooth MAP Versions --> + <string-array name="bluetooth_map_version_values"> + <item>map12</item> + <item>map13</item> + <item>map14</item> + </string-array> + <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50] --> <string-array name="bluetooth_a2dp_codec_titles"> <item>Use System Selection (Default)</item> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index bdfa21742854..8c2ff2ced17d 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -597,6 +597,11 @@ <!-- UI debug setting: Select Bluetooth AVRCP Version --> <string name="bluetooth_select_avrcp_version_dialog_title">Select Bluetooth AVRCP Version</string> + <!-- UI debug setting: Select Bluetooth MAP Version [CHAR LIMIT=NONE] --> + <string name="bluetooth_select_map_version_string">Bluetooth MAP Version</string> + <!-- UI debug setting: Select Bluetooth MAP Version [CHAR LIMIT=NONE] --> + <string name="bluetooth_select_map_version_dialog_title">Select Bluetooth MAP Version</string> + <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection --> <string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string> <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection --> diff --git a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java index 69bd0ed0c59c..ff00fb3282b1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java @@ -16,8 +16,6 @@ package com.android.settingslib; -import static android.content.Context.TELEPHONY_SERVICE; - import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -172,36 +170,38 @@ public class DeviceInfoUtils { } } - public static String getFormattedPhoneNumber(Context context, SubscriptionInfo subscriptionInfo) { + /** + * Format a phone number. + * @param subscriptionInfo {@link SubscriptionInfo} subscription information. + * @return Returns formatted phone number. + */ + public static String getFormattedPhoneNumber(Context context, + SubscriptionInfo subscriptionInfo) { String formattedNumber = null; if (subscriptionInfo != null) { - final TelephonyManager telephonyManager = - (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE); - final String rawNumber = - telephonyManager.getLine1Number(subscriptionInfo.getSubscriptionId()); + final TelephonyManager telephonyManager = context.getSystemService( + TelephonyManager.class); + final String rawNumber = telephonyManager.createForSubscriptionId( + subscriptionInfo.getSubscriptionId()).getLine1Number(); if (!TextUtils.isEmpty(rawNumber)) { formattedNumber = PhoneNumberUtils.formatNumber(rawNumber); } - } return formattedNumber; } public static String getFormattedPhoneNumbers(Context context, - List<SubscriptionInfo> subscriptionInfo) { + List<SubscriptionInfo> subscriptionInfoList) { StringBuilder sb = new StringBuilder(); - if (subscriptionInfo != null) { - final TelephonyManager telephonyManager = - (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE); - final int count = subscriptionInfo.size(); - for (int i = 0; i < count; i++) { - final String rawNumber = telephonyManager.getLine1Number( - subscriptionInfo.get(i).getSubscriptionId()); + if (subscriptionInfoList != null) { + final TelephonyManager telephonyManager = context.getSystemService( + TelephonyManager.class); + final int count = subscriptionInfoList.size(); + for (SubscriptionInfo subscriptionInfo : subscriptionInfoList) { + final String rawNumber = telephonyManager.createForSubscriptionId( + subscriptionInfo.getSubscriptionId()).getLine1Number(); if (!TextUtils.isEmpty(rawNumber)) { - sb.append(PhoneNumberUtils.formatNumber(rawNumber)); - if (i < count - 1) { - sb.append("\n"); - } + sb.append(PhoneNumberUtils.formatNumber(rawNumber)).append("\n"); } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index ee44d0a606aa..1141daa94e6d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -421,7 +421,7 @@ public class Utils { // is not available. Note that we ignore the IWLAN service state // because that state indicates the use of VoWIFI and not cell service final int state = serviceState.getState(); - final int dataState = serviceState.getDataRegState(); + final int dataState = serviceState.getDataRegistrationState(); if (state == ServiceState.STATE_OUT_OF_SERVICE || state == ServiceState.STATE_EMERGENCY_ONLY) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index abfee1d415d6..9765074a4927 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -184,13 +184,28 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } } + /** + * Connect this device. + * + * @param connectAllProfiles {@code true} to connect all profile, {@code false} otherwise. + * + * @deprecated use {@link #connect()} instead. + */ + @Deprecated public void connect(boolean connectAllProfiles) { + connect(); + } + + /** + * Connect this device. + */ + public void connect() { if (!ensurePaired()) { return; } mConnectAttempted = SystemClock.elapsedRealtime(); - connectWithoutResettingTimer(connectAllProfiles); + connectAllEnabledProfiles(); } public long getHiSyncId() { @@ -211,10 +226,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> void onBondingDockConnect() { // Attempt to connect if UUIDs are available. Otherwise, // we will connect when the ACTION_UUID intent arrives. - connect(false); + connect(); } - private void connectWithoutResettingTimer(boolean connectAllProfiles) { + private void connectAllEnabledProfiles() { synchronized (mProfileLock) { // Try to initialize the profiles if they were not. if (mProfiles.isEmpty()) { @@ -229,36 +244,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return; } - int preferredProfiles = 0; - for (LocalBluetoothProfile profile : mProfiles) { - if (connectAllProfiles ? profile.accessProfileEnabled() - : profile.isAutoConnectable()) { - if (profile.isPreferred(mDevice)) { - ++preferredProfiles; - connectInt(profile); - } - } - } - if (BluetoothUtils.D) Log.d(TAG, "Preferred profiles = " + preferredProfiles); - - if (preferredProfiles == 0) { - connectAutoConnectableProfiles(); - } - } - } - - private void connectAutoConnectableProfiles() { - if (!ensurePaired()) { - return; - } - - synchronized (mProfileLock) { - for (LocalBluetoothProfile profile : mProfiles) { - if (profile.isAutoConnectable()) { - profile.setPreferred(mDevice, true); - connectInt(profile); - } - } + mLocalAdapter.connectAllEnabledProfiles(mDevice); } } @@ -625,7 +611,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> */ if (!mProfiles.isEmpty() && ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime())) { - connectWithoutResettingTimer(false); + connectAllEnabledProfiles(); } dispatchAttributesChanged(); @@ -644,7 +630,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> refresh(); if (bondState == BluetoothDevice.BOND_BONDED && mDevice.isBondingInitiatedLocally()) { - connect(false); + connect(); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 4e16c66d736b..56b14c6b652d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -116,7 +116,7 @@ public class LocalMediaManager implements BluetoothCallback { final CachedBluetoothDevice cachedDevice = ((BluetoothMediaDevice) device).getCachedDevice(); if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) { - cachedDevice.connect(true); + cachedDevice.connect(); return; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java index 23e2949372aa..d5ff1ee6512a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java @@ -38,7 +38,7 @@ public class DataUsageUtils { final SubscriptionManager subscriptionManager = context.getSystemService( SubscriptionManager.class); final NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( - telephonyManager.getSubscriberId(subId)); + telephonyManager.createForSubscriptionId(subId).getSubscriberId()); if (!subscriptionManager.isActiveSubId(subId)) { Log.i(TAG, "Subscription is not active: " + subId); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index b11585a73946..8bd5f57f9b71 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -90,7 +90,7 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { public void setListening(boolean listening) { if (listening) { mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mWifiNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK); + mWifiNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK); mWifiNetworkScoreCache.registerListener(mCacheListener); mConnectivityManager.registerNetworkCallback( mNetworkRequest, mNetworkCallback, mHandler); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 3e359d216234..f7131392c68c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -359,7 +359,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro mNetworkScoreManager.registerNetworkScoreCache( NetworkKey.TYPE_WIFI, mScoreCache, - NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS); + NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS); } private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) { diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER new file mode 100644 index 000000000000..5c2a7b892f8f --- /dev/null +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER @@ -0,0 +1,4 @@ +# People who can approve changes for submission +arcwang@google.com +govenliu@google.com +qal@google.com diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java index 51806e0d3c03..4948987cac96 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java @@ -227,7 +227,7 @@ public class UtilsTest { @Test public void isInService_voiceOutOfServiceDataInService_returnTrue() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE); + when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo); when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn( @@ -243,7 +243,7 @@ public class UtilsTest { AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo); when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn( NetworkRegistrationInfo.REGISTRATION_STATE_HOME); - when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE); + when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); assertThat(Utils.isInService(mServiceState)).isFalse(); } @@ -251,7 +251,8 @@ public class UtilsTest { @Test public void isInService_voiceOutOfServiceDataOutOfService_returnFalse() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); + when(mServiceState.getDataRegistrationState()).thenReturn( + ServiceState.STATE_OUT_OF_SERVICE); assertThat(Utils.isInService(mServiceState)).isFalse(); } @@ -288,7 +289,7 @@ public class UtilsTest { @Test public void getCombinedServiceState_voiceOutOfServiceDataInService_returnInService() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE); + when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo); when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn( @@ -301,7 +302,7 @@ public class UtilsTest { @Test public void getCombinedServiceState_voiceOutOfServiceDataInServiceOnIwLan_returnOutOfService() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE); + when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo); when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn( @@ -314,7 +315,8 @@ public class UtilsTest { @Test public void getCombinedServiceState_voiceOutOfServiceDataOutOfService_returnOutOfService() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); + when(mServiceState.getDataRegistrationState()).thenReturn( + ServiceState.STATE_OUT_OF_SERVICE); assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo( ServiceState.STATE_OUT_OF_SERVICE); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index 98bb74ad0718..4b9f6c22d78c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -127,7 +127,7 @@ public class LocalMediaManagerTest { mLocalMediaManager.registerCallback(mCallback); mLocalMediaManager.connectDevice(device); - verify(cachedDevice).connect(true); + verify(cachedDevice).connect(); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER new file mode 100644 index 000000000000..5c2a7b892f8f --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER @@ -0,0 +1,4 @@ +# People who can approve changes for submission +arcwang@google.com +govenliu@google.com +qal@google.com diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index efd31ca6a86e..af2569dcb1f2 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -186,6 +186,9 @@ <uses-permission android:name="android.permission.MANAGE_APPOPS" /> + <!-- Permission required for storage tests - FuseDaemonHostTest --> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> + <!-- Permission needed to run network tests in CTS --> <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" /> <!-- Permission needed to test tcp keepalive offload. --> diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index d674be4c8fc0..dbfaca0b6b80 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -142,7 +142,7 @@ android_app { resource_dirs: [], platform_apis: true, - product_specific: true, + system_ext_specific: true, certificate: "platform", privileged: true, diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 403e894a68e4..262365da3a06 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -72,7 +72,7 @@ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" /> <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" /> - <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> + <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" /> <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <uses-permission android:name="android.permission.TETHER_PRIVILEGED" /> <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> diff --git a/packages/SystemUI/CleanSpec.mk b/packages/SystemUI/CleanSpec.mk new file mode 100644 index 000000000000..2a2e4e44e834 --- /dev/null +++ b/packages/SystemUI/CleanSpec.mk @@ -0,0 +1,50 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/SystemUI) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/SystemUI) +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_item.xml b/packages/SystemUI/res/layout-land/global_actions_grid_item.xml index bc1233828b4d..0f9deaa3c569 100644 --- a/packages/SystemUI/res/layout-land/global_actions_grid_item.xml +++ b/packages/SystemUI/res/layout-land/global_actions_grid_item.xml @@ -57,15 +57,5 @@ android:textColor="@color/global_actions_text" android:textAppearance="?android:attr/textAppearanceSmall" /> - - <TextView - android:visibility="gone" - android:id="@*android:id/status" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:textColor="@color/global_actions_text" - android:textAppearance="?android:attr/textAppearanceSmall" - /> </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/global_actions_grid_item.xml b/packages/SystemUI/res/layout/global_actions_grid_item.xml index 4404c87432fe..31c7cbf6ff1b 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_item.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_item.xml @@ -56,15 +56,5 @@ android:textColor="@color/global_actions_text" android:textAppearance="?android:attr/textAppearanceSmall" /> - - <TextView - android:visibility="gone" - android:id="@*android:id/status" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:textColor="@color/global_actions_text" - android:textAppearance="?android:attr/textAppearanceSmall" - /> </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index 9d9cad825444..8631e860e0a6 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -348,7 +348,7 @@ public class CarrierTextController { } if (simState == IccCardConstants.State.READY) { ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); - if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) { + if (ss != null && ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) { // hack for WFC (IWLAN) not turning off immediately once // Wi-Fi is disassociated or disabled if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java index 367a7bd4aed7..0ffe05de1357 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java @@ -26,8 +26,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; -import android.os.RemoteException; -import android.os.ServiceManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -37,7 +35,6 @@ import android.view.View; import android.view.WindowManager; import android.widget.ImageView; -import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.PhoneConstants; @@ -254,27 +251,29 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { @Override public void run() { - try { - if (DEBUG) { - Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")"); - } - final int[] result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPinReportResultForSubscriber(mSubId, mPin); - if (DEBUG) { - Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]); - } + if (DEBUG) { + Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")"); + } + TelephonyManager telephonyManager = + ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) + .createForSubscriptionId(mSubId); + final int[] result = telephonyManager.supplyPinReportResult(mPin); + if (result == null || result.length == 0) { + Log.e(TAG, "Error result for supplyPinReportResult."); post(new Runnable() { @Override public void run() { - onSimCheckResponse(result[0], result[1]); + onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); } }); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException for supplyPinReportResult:", e); + } else { + if (DEBUG) { + Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]); + } post(new Runnable() { @Override public void run() { - onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); + onSimCheckResponse(result[0], result[1]); } }); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java index 81f8c67605fe..abadcfd60a38 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java @@ -25,8 +25,6 @@ import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; -import android.os.RemoteException; -import android.os.ServiceManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -36,7 +34,6 @@ import android.view.View; import android.view.WindowManager; import android.widget.ImageView; -import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.PhoneConstants; @@ -314,25 +311,27 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { @Override public void run() { - try { - if (DEBUG) Log.v(TAG, "call supplyPukReportResult()"); - final int[] result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPukReportResultForSubscriber(mSubId, mPuk, mPin); - if (DEBUG) { - Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]); - } + if (DEBUG) Log.v(TAG, "call supplyPukReportResult()"); + TelephonyManager telephonyManager = + ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) + .createForSubscriptionId(mSubId); + final int[] result = telephonyManager.supplyPukReportResult(mPuk, mPin); + if (result == null || result.length == 0) { + Log.e(TAG, "Error result for supplyPukReportResult."); post(new Runnable() { @Override public void run() { - onSimLockChangedResponse(result[0], result[1]); + onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); } }); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException for supplyPukReportResult:", e); + } else { + if (DEBUG) { + Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]); + } post(new Runnable() { @Override public void run() { - onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); + onSimLockChangedResponse(result[0], result[1]); } }); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 8d858dcb25df..1fb50a9a61de 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -1061,7 +1061,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { // keep compatibility with apps that aren't direct boot aware. // SysUI should just ignore this broadcast because it was already received // and processed previously. - if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) { + if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { // Guarantee mTelephonyCapable state after SysUI crash and restart if (args.simState == State.ABSENT) { mHandler.obtainMessage(MSG_TELEPHONY_CAPABLE, true).sendToTarget(); diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index ff02e71147fd..589b24a04f8c 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1145,13 +1145,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, TextView messageView = (TextView) v.findViewById(R.id.message); messageView.setSelected(true); // necessary for marquee to work - TextView statusView = (TextView) v.findViewById(R.id.status); - final String status = getStatus(); - if (!TextUtils.isEmpty(status)) { - statusView.setText(status); - } else { - statusView.setVisibility(View.GONE); - } if (mIcon != null) { icon.setImageDrawable(mIcon); icon.setScaleType(ScaleType.CENTER_CROP); @@ -1236,32 +1229,26 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, LayoutInflater inflater) { willCreate(); - View v = inflater.inflate(R - .layout.global_actions_item, parent, false); + View v = inflater.inflate(com.android.systemui.R + .layout.global_actions_grid_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); - TextView statusView = (TextView) v.findViewById(R.id.status); final boolean enabled = isEnabled(); + boolean on = ((mState == State.On) || (mState == State.TurningOn)); if (messageView != null) { - messageView.setText(mMessageResId); + messageView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); messageView.setEnabled(enabled); messageView.setSelected(true); // necessary for marquee to work } - boolean on = ((mState == State.On) || (mState == State.TurningOn)); if (icon != null) { icon.setImageDrawable(context.getDrawable( (on ? mEnabledIconResId : mDisabledIconResid))); icon.setEnabled(enabled); } - if (statusView != null) { - statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); - statusView.setVisibility(View.VISIBLE); - statusView.setEnabled(enabled); - } v.setEnabled(enabled); return v; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java index 4700baae8fab..18d436ff7659 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java @@ -421,7 +421,7 @@ public class NotificationGuts extends FrameLayout { } /** Listener for animations executed in {@link #animateClose(int, int, boolean)}. */ - private static class AnimateCloseListener extends AnimatorListenerAdapter { + private class AnimateCloseListener extends AnimatorListenerAdapter { final View mView; private final GutsContent mGutsContent; @@ -433,8 +433,10 @@ public class NotificationGuts extends FrameLayout { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mView.setVisibility(View.GONE); - mGutsContent.onFinishedClosing(); + if (!isExposed()) { + mView.setVisibility(View.GONE); + mGutsContent.onFinishedClosing(); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 8f7671a5dd96..719ec3215d42 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -100,6 +100,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx protected String mKeyToRemoveOnGutsClosed; private StatusBar mStatusBar; + private Runnable mOpenRunnable; @Inject public NotificationGutsManager( @@ -343,6 +344,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls, int x, int y, boolean resetMenu) { if (mNotificationGutsExposed != null) { + mNotificationGutsExposed.removeCallbacks(mOpenRunnable); mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force); } if (resetMenu) { @@ -445,7 +447,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx // ensure that it's laid but not visible until actually laid out guts.setVisibility(View.INVISIBLE); // Post to ensure the the guts are properly laid out. - guts.post(new Runnable() { + mOpenRunnable = new Runnable() { @Override public void run() { if (row.getWindowToken() == null) { @@ -470,7 +472,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mListContainer.onHeightChanged(row, true /* needsAnimation */); mGutsMenuItem = menuItem; } - }); + }; + guts.post(mOpenRunnable); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt index f4635d1270a8..f7b8a2e29129 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt @@ -67,6 +67,9 @@ class KeyguardLiftController constructor( } private fun updateListeningState() { + if (pickupSensor == null) { + return + } val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible && !statusBarStateController.isDozing diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 17c200eaef6a..b2f4f16c8005 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -605,8 +605,7 @@ public class PhoneStatusBarPolicy break; case TelephonyIntents.ACTION_SIM_STATE_CHANGED: // Avoid rebroadcast because SysUI is direct boot aware. - if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, - false)) { + if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { break; } updateSimState(intent); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 0c47d1468a7f..68ee8bbbb69b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -62,6 +62,8 @@ import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; import java.io.PrintWriter; import java.util.ArrayList; +import androidx.annotation.VisibleForTesting; + /** * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, @@ -161,6 +163,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastLockVisible; private OnDismissAction mAfterKeyguardGoneAction; + private Runnable mKeyguardGoneCancelAction; private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>(); // Dismiss action to be launched when we stop dozing or the keyguard is gone. @@ -328,10 +331,20 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb return false; } - private void hideBouncer(boolean destroyView) { + @VisibleForTesting + void hideBouncer(boolean destroyView) { if (mBouncer == null) { return; } + if (mShowing) { + // If we were showing the bouncer and then aborting, we need to also clear out any + // potential actions unless we actually unlocked. + mAfterKeyguardGoneAction = null; + if (mKeyguardGoneCancelAction != null) { + mKeyguardGoneCancelAction.run(); + mKeyguardGoneCancelAction = null; + } + } mBouncer.hide(destroyView); cancelPendingWakeupAction(); } @@ -364,6 +377,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncer.showWithDismissAction(r, cancelAction); } else { mAfterKeyguardGoneAction = r; + mKeyguardGoneCancelAction = cancelAction; mBouncer.show(false /* resetSecuritySelection */); } } @@ -671,6 +685,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mAfterKeyguardGoneAction.onDismiss(); mAfterKeyguardGoneAction = null; } + mKeyguardGoneCancelAction = null; for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) { mAfterKeyguardGoneRunnables.get(i).run(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 582775eaa888..1c646b2d4ee2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -15,6 +15,9 @@ */ package com.android.systemui.statusbar.policy; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import android.content.Context; import android.content.Intent; import android.database.ContentObserver; @@ -703,12 +706,16 @@ public class MobileSignalController extends SignalController< @Override public void onServiceStateChanged(ServiceState state) { if (DEBUG) { - Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState() - + " dataState=" + state.getDataRegState()); + Log.d(mTag, "onServiceStateChanged voiceState=" + state.getState() + + " dataState=" + state.getDataRegistrationState()); } mServiceState = state; if (mServiceState != null) { - updateDataNetType(mServiceState.getDataNetworkType()); + NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo( + DOMAIN_PS, TRANSPORT_TYPE_WWAN); + if (regInfo != null) { + updateDataNetType(regInfo.getAccessNetworkTechnology()); + } } updateTelephony(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 7a09455017dd..45233744eabd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -517,7 +517,7 @@ public class NetworkControllerImpl extends BroadcastReceiver break; case TelephonyIntents.ACTION_SIM_STATE_CHANGED: // Avoid rebroadcast because SysUI is direct boot aware. - if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) { + if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { break; } // Might have different subscriptions now. diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index efb4ff008b23..a897b0098bb7 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -35,7 +35,6 @@ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" /> <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" /> <uses-permission android:name="android.permission.CONTROL_VPN" /> diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index cfa56451d515..4d9ea29e9496 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -339,7 +339,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ServiceState ss = mock(ServiceState.class); - when(ss.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE); + when(ss.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); mKeyguardUpdateMonitor.mServiceStates.put(TEST_SUBSCRIPTION_NULL.getSubscriptionId(), ss); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index db6177a63f96..21585ed5ccb7 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -133,7 +133,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { Assert.assertTrue("onSimStateChanged not called", mKeyguardUpdateMonitor.hasSimStateJustChanged()); - intent.putExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, true); + intent.putExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, true); mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(), intent); mTestableLooper.processAllMessages(); Assert.assertFalse("onSimStateChanged should have been skipped", diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 63f653b0b303..0da0e7647707 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -221,6 +221,31 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(mStatusBar, never()).animateKeyguardUnoccluding(); } + @Test + public void testHiding_cancelsGoneRunnable() { + OnDismissAction action = mock(OnDismissAction.class); + Runnable cancelAction = mock(Runnable.class); + mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, + true /* afterKeyguardGone */); + + mStatusBarKeyguardViewManager.hideBouncer(true); + mStatusBarKeyguardViewManager.hide(0, 30); + verify(action, never()).onDismiss(); + verify(cancelAction).run(); + } + + @Test + public void testHiding_doesntCancelWhenShowing() { + OnDismissAction action = mock(OnDismissAction.class); + Runnable cancelAction = mock(Runnable.class); + mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, + true /* afterKeyguardGone */); + + mStatusBarKeyguardViewManager.hide(0, 30); + verify(action).onDismiss(); + verify(cancelAction, never()).run(); + } + private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { public TestableStatusBarKeyguardViewManager(Context context, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 354aa835179c..59270d86844b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.policy; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; @@ -39,6 +42,7 @@ import android.net.wifi.WifiManager; import android.os.Handler; import android.provider.Settings; import android.provider.Settings.Global; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -298,12 +302,12 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } public void setVoiceRegState(int voiceRegState) { - when(mServiceState.getVoiceRegState()).thenReturn(voiceRegState); + when(mServiceState.getState()).thenReturn(voiceRegState); updateServiceState(); } public void setDataRegState(int dataRegState) { - when(mServiceState.getDataRegState()).thenReturn(dataRegState); + when(mServiceState.getDataRegistrationState()).thenReturn(dataRegState); updateServiceState(); } @@ -347,7 +351,13 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } public void updateDataConnectionState(int dataState, int dataNetType) { - when(mServiceState.getDataNetworkType()).thenReturn(dataNetType); + NetworkRegistrationInfo fakeRegInfo = new NetworkRegistrationInfo.Builder() + .setTransportType(TRANSPORT_TYPE_WWAN) + .setDomain(DOMAIN_PS) + .setAccessNetworkTechnology(dataNetType) + .build(); + when(mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN)) + .thenReturn(fakeRegInfo); mPhoneStateListener.onDataConnectionStateChanged(dataState, dataNetType); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 99e5a76b3a11..47e0c3c1600d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -1,5 +1,8 @@ package com.android.systemui.statusbar.policy; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyInt; @@ -418,7 +421,13 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { // State from NR_5G to NONE NR_STATE_RESTRICTED, showing corresponding icon doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(mServiceState).getNrState(); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); + NetworkRegistrationInfo fakeRegInfo = new NetworkRegistrationInfo.Builder() + .setTransportType(TRANSPORT_TYPE_WWAN) + .setDomain(DOMAIN_PS) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .build(); + doReturn(fakeRegInfo).when(mServiceState) + .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -480,8 +489,13 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { verifyDataIndicators(TelephonyIcons.ICON_LTE); - when(mServiceState.getDataNetworkType()) - .thenReturn(TelephonyManager.NETWORK_TYPE_HSPA); + NetworkRegistrationInfo fakeRegInfo = new NetworkRegistrationInfo.Builder() + .setTransportType(TRANSPORT_TYPE_WWAN) + .setDomain(DOMAIN_PS) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_HSPA) + .build(); + when(mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN)) + .thenReturn(fakeRegInfo); updateServiceState(); verifyDataIndicators(TelephonyIcons.ICON_H); } diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 08552cbfd394..1315ed08464a 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -20,7 +20,7 @@ java_defaults { srcs: [ "src/**/*.java", ":framework-tethering-shared-srcs", - ":net-module-utils-srcs", + ":tethering-module-utils-srcs", ":services-tethering-shared-srcs", ], static_libs: [ @@ -32,8 +32,9 @@ java_defaults { ], libs: [ "framework-tethering", + "unsupportedappusage", ], - + plugins: ["java_api_finder"], manifest: "AndroidManifestBase.xml", } @@ -45,9 +46,9 @@ android_library { // Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK). cc_library { - name: "libtetheroffloadjni", + name: "libtetherutilsjni", srcs: [ - "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp", + "jni/android_net_util_TetheringUtils.cpp", ], shared_libs: [ "libcgrouprc", @@ -87,7 +88,7 @@ java_defaults { "libcgrouprc", "libnativehelper_compat_libc++", "libvndksupport", - "libtetheroffloadjni", + "libtetherutilsjni", ], resource_dirs: [ "res", @@ -122,4 +123,5 @@ android_app { use_embedded_native_libs: true, // The permission configuration *must* be included to ensure security of the device required: ["NetworkPermissionConfig"], + apex_available: ["com.android.tethering"], } diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml index 87a8c3f5c68a..c71d0d7bc543 100644 --- a/packages/Tethering/AndroidManifest.xml +++ b/packages/Tethering/AndroidManifest.xml @@ -32,8 +32,11 @@ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.MANAGE_USB" /> <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> + <uses-permission android:name="android.permission.TETHER_PRIVILEGED" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> + <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <application diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index 5785707cb9c5..264ce440f59f 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -47,6 +47,16 @@ java_library { libs: [ "android_system_stubs_current", ], + + hostdex: true, // for hiddenapi check + visibility: [ + "//frameworks/base/packages/Tethering:__subpackages__", + //TODO(b/147200698) remove below lines when the platform is built with stubs + "//frameworks/base", + "//frameworks/base/services", + "//frameworks/base/services/core", + ], + apex_available: ["com.android.tethering"], } filegroup { diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index a49ab85d2faf..11e57186c666 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -15,8 +15,6 @@ */ package android.net; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; - import android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityManager.OnTetheringEventCallback; @@ -52,6 +50,103 @@ public class TetheringManager { private TetheringConfigurationParcel mTetheringConfiguration; private TetherStatesParcel mTetherStatesParcel; + /** + * Broadcast Action: A tetherable connection has come or gone. + * Uses {@code TetheringManager.EXTRA_AVAILABLE_TETHER}, + * {@code TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY}, + * {@code TetheringManager.EXTRA_ACTIVE_TETHER}, and + * {@code TetheringManager.EXTRA_ERRORED_TETHER} to indicate + * the current state of tethering. Each include a list of + * interface names in that state (may be empty). + */ + public static final String ACTION_TETHER_STATE_CHANGED = + "android.net.conn.TETHER_STATE_CHANGED"; + + /** + * gives a String[] listing all the interfaces configured for + * tethering and currently available for tethering. + */ + public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; + + /** + * gives a String[] listing all the interfaces currently in local-only + * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding) + */ + public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray"; + + /** + * gives a String[] listing all the interfaces currently tethered + * (ie, has DHCPv4 support and packets potentially forwarded/NATed) + */ + public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; + + /** + * gives a String[] listing all the interfaces we tried to tether and + * failed. Use {@link #getLastTetherError} to find the error code + * for any interfaces listed here. + */ + public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + + /** + * Invalid tethering type. + * @see #startTethering. + */ + public static final int TETHERING_INVALID = -1; + + /** + * Wifi tethering type. + * @see #startTethering. + */ + public static final int TETHERING_WIFI = 0; + + /** + * USB tethering type. + * @see #startTethering. + */ + public static final int TETHERING_USB = 1; + + /** + * Bluetooth tethering type. + * @see #startTethering. + */ + public static final int TETHERING_BLUETOOTH = 2; + + /** + * Wifi P2p tethering type. + * Wifi P2p tethering is set through events automatically, and don't + * need to start from #startTethering. + */ + public static final int TETHERING_WIFI_P2P = 3; + + /** + * Extra used for communicating with the TetherService. Includes the type of tethering to + * enable if any. + */ + public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; + + /** + * Extra used for communicating with the TetherService. Includes the type of tethering for + * which to cancel provisioning. + */ + public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType"; + + /** + * Extra used for communicating with the TetherService. True to schedule a recheck of tether + * provisioning. + */ + public static final String EXTRA_SET_ALARM = "extraSetAlarm"; + + /** + * Tells the TetherService to run a provision check now. + */ + public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; + + /** + * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver} + * which will receive provisioning results. Can be left empty. + */ + public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback"; + public static final int TETHER_ERROR_NO_ERROR = 0; public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; @@ -470,7 +565,7 @@ public class TetheringManager { * failed. Re-attempting to tether may cause them to reset to the Tethered * state. Alternatively, causing the interface to be destroyed and recreated * may cause them to reset to the available state. - * {@link ConnectivityManager#getLastTetherError} can be used to get more + * {@link TetheringManager#getLastTetherError} can be used to get more * information on the cause of the errors. * * @return an array of 0 or more String indicating the interface names diff --git a/packages/Tethering/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt index dd9eab74e851..c6efa41e580a 100644 --- a/packages/Tethering/jarjar-rules.txt +++ b/packages/Tethering/jarjar-rules.txt @@ -11,5 +11,8 @@ rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering. rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1 rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 +rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 + +rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1 diff --git a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp index 663154a49048..1cf8f988432c 100644 --- a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp +++ b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp @@ -19,13 +19,16 @@ #include <hidl/HidlSupport.h> #include <jni.h> #include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedUtfChars.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netlink.h> +#include <net/if.h> +#include <netinet/icmp6.h> #include <sys/socket.h> #include <android-base/unique_fd.h> #include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h> -#define LOG_TAG "OffloadHardwareInterface" +#define LOG_TAG "TetheringUtils" #include <utils/Log.h> namespace android { @@ -87,7 +90,7 @@ hidl_handle handleFromFileDescriptor(base::unique_fd fd) { } // namespace -static jboolean android_server_connectivity_tethering_OffloadHardwareInterface_configOffload( +static jboolean android_net_util_configOffload( JNIEnv* /* env */) { sp<IOffloadConfig> configInterface = IOffloadConfig::getService(); if (configInterface.get() == nullptr) { @@ -130,18 +133,109 @@ static jboolean android_server_connectivity_tethering_OffloadHardwareInterface_c return rval; } +static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd, + jint ifIndex) +{ + static const int kLinkLocalHopLimit = 255; + + int fd = jniGetFDFromFileDescriptor(env, javaFd); + + // Set an ICMPv6 filter that only passes Router Solicitations. + struct icmp6_filter rs_only; + ICMP6_FILTER_SETBLOCKALL(&rs_only); + ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &rs_only); + socklen_t len = sizeof(rs_only); + if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &rs_only, len) != 0) { + jniThrowExceptionFmt(env, "java/net/SocketException", + "setsockopt(ICMP6_FILTER): %s", strerror(errno)); + return; + } + + // Most/all of the rest of these options can be set via Java code, but + // because we're here on account of setting an icmp6_filter go ahead + // and do it all natively for now. + + // Set the multicast hoplimit to 255 (link-local only). + int hops = kLinkLocalHopLimit; + len = sizeof(hops); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, len) != 0) { + jniThrowExceptionFmt(env, "java/net/SocketException", + "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno)); + return; + } + + // Set the unicast hoplimit to 255 (link-local only). + hops = kLinkLocalHopLimit; + len = sizeof(hops); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, len) != 0) { + jniThrowExceptionFmt(env, "java/net/SocketException", + "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno)); + return; + } + + // Explicitly disable multicast loopback. + int off = 0; + len = sizeof(off); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, len) != 0) { + jniThrowExceptionFmt(env, "java/net/SocketException", + "setsockopt(IPV6_MULTICAST_LOOP): %s", strerror(errno)); + return; + } + + // Specify the IPv6 interface to use for outbound multicast. + len = sizeof(ifIndex); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, len) != 0) { + jniThrowExceptionFmt(env, "java/net/SocketException", + "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errno)); + return; + } + + // Additional options to be considered: + // - IPV6_TCLASS + // - IPV6_RECVPKTINFO + // - IPV6_RECVHOPLIMIT + + // Bind to [::]. + const struct sockaddr_in6 sin6 = { + .sin6_family = AF_INET6, + .sin6_port = 0, + .sin6_flowinfo = 0, + .sin6_addr = IN6ADDR_ANY_INIT, + .sin6_scope_id = 0, + }; + auto sa = reinterpret_cast<const struct sockaddr *>(&sin6); + len = sizeof(sin6); + if (bind(fd, sa, len) != 0) { + jniThrowExceptionFmt(env, "java/net/SocketException", + "bind(IN6ADDR_ANY): %s", strerror(errno)); + return; + } + + // Join the all-routers multicast group, ff02::2%index. + struct ipv6_mreq all_rtrs = { + .ipv6mr_multiaddr = {{{0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}}, + .ipv6mr_interface = ifIndex, + }; + len = sizeof(all_rtrs); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &all_rtrs, len) != 0) { + jniThrowExceptionFmt(env, "java/net/SocketException", + "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno)); + return; + } +} + /* * JNI registration. */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "configOffload", "()Z", - (void*) android_server_connectivity_tethering_OffloadHardwareInterface_configOffload }, + { "configOffload", "()Z", (void*) android_net_util_configOffload }, + { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket }, }; -int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv* env) { +int register_android_net_util_TetheringUtils(JNIEnv* env) { return jniRegisterNativeMethods(env, - "com/android/server/connectivity/tethering/OffloadHardwareInterface", + "android/net/util/TetheringUtils", gMethods, NELEM(gMethods)); } @@ -152,7 +246,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { return JNI_ERR; } - if (register_android_server_connectivity_tethering_OffloadHardwareInterface(env) < 0) { + if (register_android_net_util_TetheringUtils(env) < 0) { return JNI_ERR; } diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml index 37e679dbeb63..6fa1f77bdd38 100644 --- a/packages/Tethering/res/values/config.xml +++ b/packages/Tethering/res/values/config.xml @@ -1,7 +1,152 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> <resources> <!-- OEMs that wish to change the below settings must do so via a runtime resource overlay package and *NOT* by changing this file. This file is part of the tethering mainline module. + TODO: define two resources for each config item: a default_* resource and a config_* resource, + config_* is empty by default but may be overridden by RROs. --> + <!-- List of regexpressions describing the interface (if any) that represent tetherable + USB interfaces. If the device doesn't want to support tethering over USB this should + be empty. An example would be "usb.*" --> + <string-array translatable="false" name="config_tether_usb_regexs"> + <item>"usb\\d"</item> + <item>"rndis\\d"</item> + </string-array> + + <!-- List of regexpressions describing the interface (if any) that represent tetherable + Wifi interfaces. If the device doesn't want to support tethering over Wifi this + should be empty. An example would be "softap.*" --> + <string-array translatable="false" name="config_tether_wifi_regexs"> + <item>"wlan\\d"</item> + <item>"softap\\d"</item> + </string-array> + + <!-- List of regexpressions describing the interface (if any) that represent tetherable + Wifi P2P interfaces. If the device doesn't want to support tethering over Wifi P2p this + should be empty. An example would be "p2p-p2p.*" --> + <string-array translatable="false" name="config_tether_wifi_p2p_regexs"> + </string-array> + + <!-- List of regexpressions describing the interface (if any) that represent tetherable + bluetooth interfaces. If the device doesn't want to support tethering over bluetooth this + should be empty. --> + <string-array translatable="false" name="config_tether_bluetooth_regexs"> + <item>"bt-pan"</item> + </string-array> + + <!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. --> + <bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool> + + <!-- Dhcp range (min, max) to use for tethering purposes --> + <string-array translatable="false" name="config_tether_dhcp_range"> + </string-array> + + <!-- Array of ConnectivityManager.TYPE_{BLUETOOTH, ETHERNET, MOBILE, MOBILE_DUN, MOBILE_HIPRI, + WIFI} values allowable for tethering. + + Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or + [1,7,0] for TYPE_WIFI, TYPE_BLUETOOTH, and TYPE_MOBILE. + + This list is also modified by code within the framework, including: + + - TYPE_ETHERNET (9) is prepended to this list, and + + - the return value of TelephonyManager.isTetheringApnRequired() + determines how the array is further modified: + + * TRUE (DUN REQUIRED). + TYPE_MOBILE is removed (if present). + TYPE_MOBILE_HIPRI is removed (if present). + TYPE_MOBILE_DUN is appended (if not already present). + + * FALSE (DUN NOT REQUIRED). + TYPE_MOBILE_DUN is removed (if present). + If both of TYPE_MOBILE{,_HIPRI} are not present: + TYPE_MOBILE is appended. + TYPE_MOBILE_HIPRI is appended. + + For other changes applied to this list, now and in the future, see + com.android.server.connectivity.tethering.TetheringConfiguration. + + Note also: the order of this is important. The first upstream type + for which a satisfying network exists is used. + --> + <integer-array translatable="false" name="config_tether_upstream_types"> + </integer-array> + + <!-- When true, the tethering upstream network follows the current default + Internet network (except when the current default network is mobile, + in which case a DUN network will be used if required). + + When true, overrides the config_tether_upstream_types setting above. + --> + <bool translatable="false" name="config_tether_upstream_automatic">true</bool> + + + <!-- If the mobile hotspot feature requires provisioning, a package name and class name + can be provided to launch a supported application that provisions the devices. + EntitlementManager will send an intent to Settings with the specified package name and + class name in extras to launch provision app. + TODO: note what extras here. + + See EntitlementManager#runUiTetherProvisioning and + packages/apps/Settings/src/com/android/settings/network/TetherProvisioningActivity.java + for more details. + + For ui-less/periodic recheck support see config_mobile_hotspot_provision_app_no_ui + --> + <!-- The first element is the package name and the second element is the class name + of the provisioning app --> + <string-array translatable="false" name="config_mobile_hotspot_provision_app"> + <!-- + <item>com.example.provisioning</item> + <item>com.example.provisioning.Activity</item> + --> + </string-array> + + <!-- If the mobile hotspot feature requires provisioning, an action can be provided + that will be broadcast in non-ui cases for checking the provisioning status. + EntitlementManager will pass the specified name to Settings and Settings would + launch provisioning app by sending an intent with the package name. + + A second broadcast, action defined by config_mobile_hotspot_provision_response, + will be sent back to notify if provisioning succeeded or not. The response will + match that of the activity in config_mobile_hotspot_provision_app, but instead + contained within the int extra "EntitlementResult". + TODO: provide the system api for "EntitlementResult" extra and note it here. + + See EntitlementManager#runSilentTetherProvisioning and + packages/apps/Settings/src/com/android/settings/wifi/tether/TetherService.java for more + details. + --> + <string translatable="false" name="config_mobile_hotspot_provision_app_no_ui"></string> + + <!-- Sent in response to a provisioning check. The caller must hold the + permission android.permission.TETHER_PRIVILEGED for Settings to + receive this response. + + See config_mobile_hotspot_provision_response + --> + <string translatable="false" name="config_mobile_hotspot_provision_response"></string> + + <!-- Number of hours between each background provisioning call --> + <integer translatable="false" name="config_mobile_hotspot_provision_check_period">24</integer> + + <!-- ComponentName of the service used to run no ui tether provisioning. --> + <string translatable="false" name="config_wifi_tether_enable">com.android.settings/.wifi.tether.TetherService</string> </resources> diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml new file mode 100644 index 000000000000..e089d9d19950 --- /dev/null +++ b/packages/Tethering/res/values/overlayable.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <overlayable name="TetheringConfig"> + <policy type="product|system|vendor"> + <item type="array" name="config_tether_usb_regexs"/> + <item type="array" name="config_tether_wifi_regexs"/> + <item type="array" name="config_tether_wifi_p2p_regexs"/> + <item type="array" name="config_tether_bluetooth_regexs"/> + <item type="array" name="config_tether_dhcp_range"/> + <item type="bool" name="config_tether_enable_legacy_dhcp_server"/> + <item type="array" name="config_tether_upstream_types"/> + <item type="bool" name="config_tether_upstream_automatic"/> + <!-- Configuration values for tethering entitlement check --> + <item type="array" name="config_mobile_hotspot_provision_app"/> + <item type="string" name="config_mobile_hotspot_provision_app_no_ui"/> + <item type="string" name="config_mobile_hotspot_provision_response"/> + <item type="integer" name="config_mobile_hotspot_provision_check_period"/> + <item type="string" name="config_wifi_tether_enable"/> + </policy> + </overlayable> +</resources> diff --git a/packages/Tethering/res/values/strings.xml b/packages/Tethering/res/values/strings.xml index ca866a946ea2..792bce9fc334 100644 --- a/packages/Tethering/res/values/strings.xml +++ b/packages/Tethering/res/values/strings.xml @@ -1,4 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> <resources> <!-- Shown when the device is tethered --> <!-- Strings for tethered notification title [CHAR LIMIT=200] --> @@ -9,8 +23,11 @@ <!-- This notification is shown when tethering has been disabled on a user's device. The device is managed by the user's employer. Tethering can't be turned on unless the IT administrator allows it. The noun "admin" is another reference for "IT administrator." --> - <!-- Strings for tether disabling notification title [CHAR LIMIT=200] --> + <!-- Strings for tether disabling notification title [CHAR LIMIT=200] --> <string name="disable_tether_notification_title">Tethering is disabled</string> - <!-- Strings for tether disabling notification message [CHAR LIMIT=200] --> + <!-- Strings for tether disabling notification message [CHAR LIMIT=200] --> <string name="disable_tether_notification_message">Contact your admin for details</string> + + <!-- Strings for tether notification channel name [CHAR LIMIT=200] --> + <string name="notification_channel_tethering_status">Hotspot & tethering status</string> </resources>
\ No newline at end of file diff --git a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java index 1fe2328f1cdb..d6bc063210b3 100644 --- a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -20,11 +20,11 @@ import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; import android.annotation.NonNull; import android.net.LinkAddress; - -import com.google.android.collect.Sets; +import android.util.ArraySet; import java.net.Inet4Address; import java.util.Collection; +import java.util.Collections; import java.util.Set; /** @@ -68,7 +68,7 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { * but it must always be set explicitly. */ public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Inet4Address... defaultRouters) { - return setDefaultRouters(Sets.newArraySet(defaultRouters)); + return setDefaultRouters(newArraySet(defaultRouters)); } /** @@ -96,7 +96,7 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { * <p>This may be an empty list of servers, but it must always be set explicitly. */ public DhcpServingParamsParcelExt setDnsServers(@NonNull Inet4Address... dnsServers) { - return setDnsServers(Sets.newArraySet(dnsServers)); + return setDnsServers(newArraySet(dnsServers)); } /** @@ -126,7 +126,7 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { * and do not need to be set here. */ public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) { - return setExcludedAddrs(Sets.newArraySet(excludedAddrs)); + return setExcludedAddrs(newArraySet(excludedAddrs)); } /** @@ -169,4 +169,10 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { } return res; } + + private static ArraySet<Inet4Address> newArraySet(Inet4Address... addrs) { + ArraySet<Inet4Address> addrSet = new ArraySet<>(addrs.length); + Collections.addAll(addrSet, addrs); + return addrSet; + } } diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 8fde52040ecc..0491ad7c3413 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -17,40 +17,38 @@ package android.net.ip; import static android.net.InetAddresses.parseNumericAddress; +import static android.net.RouteInfo.RTN_UNICAST; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; 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.TetheringMessageBase.BASE_IPSERVER; -import android.net.ConnectivityManager; import android.net.INetd; import android.net.INetworkStackStatusCallback; -import android.net.INetworkStatsService; -import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.RouteInfo; +import android.net.TetheringManager; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.DhcpServingParamsParcelExt; import android.net.dhcp.IDhcpServer; import android.net.ip.RouterAdvertisementDaemon.RaParams; +import android.net.shared.NetdUtils; +import android.net.shared.RouteUtils; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; -import android.net.util.NetdService; import android.net.util.SharedLog; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.Log; -import android.util.Slog; import android.util.SparseArray; import com.android.internal.util.MessageUtils; -import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -119,7 +117,7 @@ public class IpServer extends StateMachine { * * @param who the calling instance of IpServer * @param state one of STATE_* - * @param lastError one of ConnectivityManager.TETHER_ERROR_* + * @param lastError one of TetheringManager.TETHER_ERROR_* */ public void updateInterfaceState(IpServer who, int state, int lastError) { } @@ -144,36 +142,31 @@ public class IpServer extends StateMachine { return InterfaceParams.getByName(ifName); } - public INetd getNetdService() { - return NetdService.getInstance(); - } - /** Create a DhcpServer instance to be used by IpServer. */ public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb); } - private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100; // request from the user that it wants to tether - public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2; + public static final int CMD_TETHER_REQUESTED = BASE_IPSERVER + 1; // request from the user that it wants to untether - public static final int CMD_TETHER_UNREQUESTED = BASE_IFACE + 3; + public static final int CMD_TETHER_UNREQUESTED = BASE_IPSERVER + 2; // notification that this interface is down - public static final int CMD_INTERFACE_DOWN = BASE_IFACE + 4; + public static final int CMD_INTERFACE_DOWN = BASE_IPSERVER + 3; // notification from the master SM that it had trouble enabling IP Forwarding - public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IFACE + 7; + public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IPSERVER + 4; // notification from the master SM that it had trouble disabling IP Forwarding - public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8; + public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IPSERVER + 5; // notification from the master SM that it had trouble starting tethering - public static final int CMD_START_TETHERING_ERROR = BASE_IFACE + 9; + public static final int CMD_START_TETHERING_ERROR = BASE_IPSERVER + 6; // notification from the master SM that it had trouble stopping tethering - public static final int CMD_STOP_TETHERING_ERROR = BASE_IFACE + 10; + public static final int CMD_STOP_TETHERING_ERROR = BASE_IPSERVER + 7; // notification from the master SM that it had trouble setting the DNS forwarders - public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11; + public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IPSERVER + 8; // the upstream connection has changed - public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12; + public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IPSERVER + 9; // new IPv6 tethering parameters need to be processed - public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13; + public static final int CMD_IPV6_TETHER_UPDATE = BASE_IPSERVER + 10; private final State mInitialState; private final State mLocalHotspotState; @@ -181,9 +174,7 @@ public class IpServer extends StateMachine { private final State mUnavailableState; private final SharedLog mLog; - private final INetworkManagementService mNMService; private final INetd mNetd; - private final INetworkStatsService mStatsService; private final Callback mCallback; private final InterfaceController mInterfaceCtrl; @@ -211,16 +202,14 @@ public class IpServer extends StateMachine { private int mDhcpServerStartIndex = 0; private IDhcpServer mDhcpServer; private RaParams mLastRaParams; + private LinkAddress mIpv4Address; public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, - INetworkManagementService nMService, INetworkStatsService statsService, - Callback callback, boolean usingLegacyDhcp, Dependencies deps) { + INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) { super(ifaceName, looper); mLog = log.forSubComponent(ifaceName); - mNMService = nMService; - mNetd = deps.getNetdService(); - mStatsService = statsService; + mNetd = netd; mCallback = callback; mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog); mIfaceName = ifaceName; @@ -229,7 +218,7 @@ public class IpServer extends StateMachine { mUsingLegacyDhcp = usingLegacyDhcp; mDeps = deps; resetLinkProperties(); - mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; + mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; mServingMode = STATE_AVAILABLE; mInitialState = new InitialState(); @@ -250,7 +239,7 @@ public class IpServer extends StateMachine { } /** - * Tethering downstream type. It would be one of ConnectivityManager#TETHERING_*. + * Tethering downstream type. It would be one of TetheringManager#TETHERING_*. */ public int interfaceType() { return mInterfaceType; @@ -348,13 +337,13 @@ public class IpServer extends StateMachine { } }); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw new IllegalStateException(e); } }); } private void handleError() { - mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR; + mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; transitionTo(mInitialState); } } @@ -389,14 +378,15 @@ public class IpServer extends StateMachine { public void callback(int statusCode) { if (statusCode != STATUS_SUCCESS) { mLog.e("Error stopping DHCP server: " + statusCode); - mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR; + mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; // Not much more we can do here } } }); mDhcpServer = null; } catch (RemoteException e) { - e.rethrowFromSystemServer(); + mLog.e("Error stopping DHCP", e); + // Not much more we can do here } } } @@ -415,83 +405,70 @@ public class IpServer extends StateMachine { // NOTE: All of configureIPv4() will be refactored out of existence // into calls to InterfaceController, shared with startIPv4(). mInterfaceCtrl.clearIPv4Address(); + mIpv4Address = null; } - // TODO: Refactor this in terms of calls to InterfaceController. 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. - String ipAsString = null; + final Inet4Address srvAddr; int prefixLen = 0; - if (mInterfaceType == ConnectivityManager.TETHERING_USB) { - ipAsString = USB_NEAR_IFACE_ADDR; - prefixLen = USB_PREFIX_LENGTH; - } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { - ipAsString = getRandomWifiIPv4Address(); - prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; - } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI_P2P) { - ipAsString = WIFI_P2P_IFACE_ADDR; - prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH; - } else { - // BT configures the interface elsewhere: only start DHCP. - final Inet4Address srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR); - return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); - } - - final LinkAddress linkAddr; try { - final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName); - if (ifcg == null) { - mLog.e("Received null interface config"); - return false; - } - - InetAddress addr = parseNumericAddress(ipAsString); - linkAddr = new LinkAddress(addr, prefixLen); - ifcg.setLinkAddress(linkAddr); - if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { - // The WiFi stack has ownership of the interface up/down state. - // It is unclear whether the Bluetooth or USB stacks will manage their own - // state. - ifcg.ignoreInterfaceUpDownStatus(); + if (mInterfaceType == TetheringManager.TETHERING_USB) { + 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 (enabled) { - ifcg.setInterfaceUp(); - } else { - ifcg.setInterfaceDown(); - } + // 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, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); } - ifcg.clearFlag("running"); + mIpv4Address = new LinkAddress(srvAddr, prefixLen); + } catch (IllegalArgumentException e) { + mLog.e("Error selecting ipv4 address", e); + if (!enabled) stopDhcp(); + return false; + } - // TODO: this may throw if the interface is already gone. Do proper handling and - // simplify the DHCP server start/stop. - mNMService.setInterfaceConfig(mIfaceName, ifcg); + final Boolean setIfaceUp; + if (mInterfaceType == TetheringManager.TETHERING_WIFI + || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) { + // The WiFi stack has ownership of the interface up/down state. + // It is unclear whether the Bluetooth or USB stacks will manage their own + // state. + setIfaceUp = null; + } else { + setIfaceUp = enabled; + } + if (!mInterfaceCtrl.setInterfaceConfiguration(mIpv4Address, setIfaceUp)) { + mLog.e("Error configuring interface"); + if (!enabled) stopDhcp(); + return false; + } - if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) { - return false; - } - } catch (Exception e) { - mLog.e("Error configuring interface " + e); - if (!enabled) { - try { - // Calling stopDhcp several times is fine - stopDhcp(); - } catch (Exception dhcpError) { - mLog.e("Error stopping DHCP", dhcpError); - } - } + if (!configureDhcp(enabled, srvAddr, prefixLen)) { return false; } // Directly-connected route. - final RouteInfo route = new RouteInfo(linkAddr); + final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), + mIpv4Address.getPrefixLength()); + final RouteInfo route = new RouteInfo(ipv4Prefix, null, null, RTN_UNICAST); if (enabled) { - mLinkProperties.addLinkAddress(linkAddr); + mLinkProperties.addLinkAddress(mIpv4Address); mLinkProperties.addRoute(route); } else { - mLinkProperties.removeLinkAddress(linkAddr); + mLinkProperties.removeLinkAddress(mIpv4Address); mLinkProperties.removeRoute(route); } return true; @@ -583,14 +560,12 @@ public class IpServer extends StateMachine { if (!deprecatedPrefixes.isEmpty()) { final ArrayList<RouteInfo> toBeRemoved = getLocalRoutesFor(mIfaceName, deprecatedPrefixes); - try { - final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved); - if (removalFailures > 0) { - mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", - removalFailures)); - } - } catch (RemoteException e) { - mLog.e("Failed to remove IPv6 routes from local table: " + e); + // Remove routes from local network. + final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork( + mNetd, toBeRemoved); + if (removalFailures > 0) { + mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", + removalFailures)); } for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route); @@ -607,13 +582,18 @@ public class IpServer extends StateMachine { final ArrayList<RouteInfo> toBeAdded = getLocalRoutesFor(mIfaceName, addedPrefixes); try { - // It's safe to call addInterfaceToLocalNetwork() even if - // the interface is already in the local_network. Note also - // that adding routes that already exist does not cause an - // error (EEXIST is silently ignored). - mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded); - } catch (Exception e) { - mLog.e("Failed to add IPv6 routes to local table: " + e); + // It's safe to call networkAddInterface() even if + // the interface is already in the local_network. + mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName); + try { + // Add routes from local network. Note that adding routes that + // already exist does not cause an error (EEXIST is silently ignored). + RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded); + } catch (IllegalStateException e) { + mLog.e("Failed to add IPv6 routes to local table: " + e); + } + } catch (ServiceSpecificException | RemoteException e) { + mLog.e("Failed to add " + mIfaceName + " to local table: ", e); } for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route); @@ -727,7 +707,7 @@ public class IpServer extends StateMachine { logMessage(this, message.what); switch (message.what) { case CMD_TETHER_REQUESTED: - mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; + mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; switch (message.arg1) { case STATE_LOCAL_ONLY: transitionTo(mLocalHotspotState); @@ -756,15 +736,17 @@ public class IpServer extends StateMachine { @Override public void enter() { if (!startIPv4()) { - mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR; + mLastError = TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; return; } try { - mNMService.tetherInterface(mIfaceName); - } catch (Exception e) { + final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), + mIpv4Address.getPrefixLength()); + NetdUtils.tetherInterface(mNetd, mIfaceName, ipv4Prefix); + } catch (RemoteException | ServiceSpecificException e) { mLog.e("Error Tethering: " + e); - mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; + mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; return; } @@ -783,9 +765,9 @@ public class IpServer extends StateMachine { stopIPv6(); try { - mNMService.untetherInterface(mIfaceName); - } catch (Exception e) { - mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; + NetdUtils.untetherInterface(mNetd, mIfaceName); + } catch (RemoteException | ServiceSpecificException e) { + mLastError = TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; mLog.e("Failed to untether interface: " + e); } @@ -815,7 +797,7 @@ public class IpServer extends StateMachine { case CMD_START_TETHERING_ERROR: case CMD_STOP_TETHERING_ERROR: case CMD_SET_DNS_FORWARDERS_ERROR: - mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR; + mLastError = TetheringManager.TETHER_ERROR_MASTER_ERROR; transitionTo(mInitialState); break; default: @@ -834,7 +816,7 @@ public class IpServer extends StateMachine { @Override public void enter() { super.enter(); - if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) { transitionTo(mInitialState); } @@ -870,7 +852,7 @@ public class IpServer extends StateMachine { @Override public void enter() { super.enter(); - if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) { transitionTo(mInitialState); } @@ -897,20 +879,14 @@ public class IpServer extends StateMachine { // to remove their rules, which generates errors. // Just do the best we can. try { - // About to tear down NAT; gather remaining statistics. - mStatsService.forceUpdate(); - } catch (Exception e) { - if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString()); - } - try { - mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface); - } catch (Exception e) { - if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString()); + mNetd.ipfwdRemoveInterfaceForward(mIfaceName, upstreamIface); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Exception in ipfwdRemoveInterfaceForward: " + e.toString()); } try { - mNMService.disableNat(mIfaceName, upstreamIface); - } catch (Exception e) { - if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString()); + mNetd.tetherRemoveForward(mIfaceName, upstreamIface); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Exception in disableNat: " + e.toString()); } } @@ -946,12 +922,12 @@ public class IpServer extends StateMachine { for (String ifname : added) { try { - mNMService.enableNat(mIfaceName, ifname); - mNMService.startInterfaceForwarding(mIfaceName, ifname); - } catch (Exception e) { - mLog.e("Exception enabling NAT: " + e); + mNetd.tetherAddForward(mIfaceName, ifname); + mNetd.ipfwdAddInterfaceForward(mIfaceName, ifname); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Exception enabling NAT: " + e.toString()); cleanupUpstream(); - mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; + mLastError = TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR; transitionTo(mInitialState); return true; } @@ -996,7 +972,7 @@ public class IpServer extends StateMachine { class UnavailableState extends State { @Override public void enter() { - mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; + mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; sendInterfaceState(STATE_UNAVAILABLE); } } @@ -1007,7 +983,7 @@ public class IpServer extends StateMachine { String ifname, HashSet<IpPrefix> prefixes) { final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>(); for (IpPrefix ipp : prefixes) { - localRoutes.add(new RouteInfo(ipp, null, ifname)); + localRoutes.add(new RouteInfo(ipp, null, ifname, RTN_UNICAST)); } return localRoutes; } @@ -1019,7 +995,7 @@ public class IpServer extends StateMachine { try { return Inet6Address.getByAddress(null, dnsBytes, 0); } catch (UnknownHostException e) { - Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix); + Log.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix); return null; } } diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java index 414741309ef0..6f017dcb623f 100644 --- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java +++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java @@ -22,14 +22,14 @@ import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.SOCK_RAW; import static android.system.OsConstants.SOL_SOCKET; -import static android.system.OsConstants.SO_BINDTODEVICE; import static android.system.OsConstants.SO_SNDTIMEO; import android.net.IpPrefix; import android.net.LinkAddress; -import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.InterfaceParams; +import android.net.util.SocketUtils; +import android.net.util.TetheringUtils; import android.system.ErrnoException; import android.system.Os; import android.system.StructTimeval; @@ -38,8 +38,6 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.TrafficStatsConstants; -import libcore.io.IoBridge; - import java.io.FileDescriptor; import java.io.IOException; import java.net.Inet6Address; @@ -611,9 +609,8 @@ public class RouterAdvertisementDaemon { // Setting SNDTIMEO is purely for defensive purposes. Os.setsockoptTimeval( mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms)); - Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mInterface.name); - NetworkUtils.protectFromVpn(mSocket); - NetworkUtils.setupRaSocket(mSocket, mInterface.index); + SocketUtils.bindSocketToInterface(mSocket, mInterface.name); + TetheringUtils.setupRaSocket(mSocket, mInterface.index); } catch (ErrnoException | IOException e) { Log.e(TAG, "Failed to create RA daemon socket: " + e); return false; @@ -627,7 +624,7 @@ public class RouterAdvertisementDaemon { private void closeSocket() { if (mSocket != null) { try { - IoBridge.closeAndSignalBlockedThreads(mSocket); + SocketUtils.closeSocket(mSocket); } catch (IOException ignored) { } } mSocket = null; @@ -671,7 +668,7 @@ public class RouterAdvertisementDaemon { } private final class UnicastResponder extends Thread { - private final InetSocketAddress mSolicitor = new InetSocketAddress(); + private final InetSocketAddress mSolicitor = new InetSocketAddress(0); // The recycled buffer for receiving Router Solicitations from clients. // If the RS is larger than IPV6_MIN_MTU the packets are truncated. // This is fine since currently only byte 0 is examined anyway. diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java new file mode 100644 index 000000000000..1b763ce920da --- /dev/null +++ b/packages/Tethering/src/android/net/util/TetheringMessageBase.java @@ -0,0 +1,25 @@ +/* + * 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.net.util; + +/** + * This class defines Message.what base addresses for various state machine. + */ +public class TetheringMessageBase { + public static final int BASE_MASTER = 0; + public static final int BASE_IPSERVER = 100; + +} diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java new file mode 100644 index 000000000000..fa543bdce735 --- /dev/null +++ b/packages/Tethering/src/android/net/util/TetheringUtils.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.util; + +import java.io.FileDescriptor; +import java.net.SocketException; + +/** + * Native methods for tethering utilization. + * + * {@hide} + */ +public class TetheringUtils { + + /** + * Offload management process need to know conntrack rules to support NAT, but it may not have + * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and + * share them with offload management process. + */ + public static native boolean configOffload(); + + /** + * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. + * @param fd the socket's {@link FileDescriptor}. + * @param ifIndex the interface index. + */ + public static native void setupRaSocket(FileDescriptor fd, int ifIndex) + throws SocketException; + + /** + * Read s as an unsigned 16-bit integer. + */ + public static int uint16(short s) { + return s & 0xffff; + } +} diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java index ba5d08dce4ca..1cabc8d0b5b7 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java @@ -16,18 +16,16 @@ package com.android.server.connectivity.tethering; -import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE; -import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK; -import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_INVALID; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; - -import static com.android.internal.R.string.config_wifi_tether_enable; +import static android.net.TetheringManager.EXTRA_ADD_TETHER_TYPE; +import static android.net.TetheringManager.EXTRA_PROVISION_CALLBACK; +import static android.net.TetheringManager.EXTRA_RUN_PROVISION; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_INVALID; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED; import android.app.AlarmManager; import android.app.PendingIntent; @@ -36,9 +34,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Resources; import android.net.util.SharedLog; -import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -48,7 +44,6 @@ import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.SystemClock; import android.os.SystemProperties; -import android.os.UserHandle; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.util.ArraySet; @@ -56,12 +51,13 @@ import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; +import com.android.networkstack.tethering.R; import java.io.PrintWriter; /** * Re-check tethering provisioning for enabled downstream tether types. - * Reference ConnectivityManager.TETHERING_{@code *} for each tether type. + * Reference TetheringManager.TETHERING_{@code *} for each tether type. * * All methods of this class must be accessed from the thread of tethering * state machine. @@ -77,9 +73,7 @@ public class EntitlementManager { "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"; private static final String EXTRA_SUBID = "subId"; - // {@link ComponentName} of the Service used to run tether provisioning. - private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString( - Resources.getSystem().getString(config_wifi_tether_enable)); + private final ComponentName mSilentProvisioningService; private static final int MS_PER_HOUR = 60 * 60 * 1000; private static final int EVENT_START_PROVISIONING = 0; private static final int EVENT_STOP_PROVISIONING = 1; @@ -88,9 +82,9 @@ public class EntitlementManager { private static final int EVENT_GET_ENTITLEMENT_VALUE = 4; // The ArraySet contains enabled downstream types, ex: - // {@link ConnectivityManager.TETHERING_WIFI} - // {@link ConnectivityManager.TETHERING_USB} - // {@link ConnectivityManager.TETHERING_BLUETOOTH} + // {@link TetheringManager.TETHERING_WIFI} + // {@link TetheringManager.TETHERING_USB} + // {@link TetheringManager.TETHERING_BLUETOOTH} private final ArraySet<Integer> mCurrentTethers; private final Context mContext; private final int mPermissionChangeMessageCode; @@ -98,8 +92,8 @@ public class EntitlementManager { private final SparseIntArray mEntitlementCacheValue; private final EntitlementHandler mHandler; private final StateMachine mTetherMasterSM; - // Key: ConnectivityManager.TETHERING_*(downstream). - // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). + // Key: TetheringManager.TETHERING_*(downstream). + // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). private final SparseIntArray mCellularPermitted; private PendingIntent mProvisioningRecheckAlarm; private boolean mCellularUpstreamPermitted = true; @@ -124,6 +118,8 @@ public class EntitlementManager { mHandler = new EntitlementHandler(masterHandler.getLooper()); mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), null, mHandler); + mSilentProvisioningService = ComponentName.unflattenFromString( + mContext.getResources().getString(R.string.config_wifi_tether_enable)); } public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) { @@ -135,7 +131,7 @@ public class EntitlementManager { /** * Ui entitlement check fails in |downstream|. * - * @param downstream tethering type from ConnectivityManager.TETHERING_{@code *}. + * @param downstream tethering type from TetheringManager.TETHERING_{@code *}. */ void onUiEntitlementFailed(int downstream); } @@ -171,7 +167,7 @@ public class EntitlementManager { * This is called when tethering starts. * Launch provisioning app if upstream is cellular. * - * @param downstreamType tethering type from ConnectivityManager.TETHERING_{@code *} + * @param downstreamType tethering type from TetheringManager.TETHERING_{@code *} * @param showProvisioningUi a boolean indicating whether to show the * provisioning app UI if there is one. */ @@ -196,9 +192,9 @@ public class EntitlementManager { // till upstream change to cellular. if (mUsingCellularAsUpstream) { if (showProvisioningUi) { - runUiTetherProvisioning(type, config.subId); + runUiTetherProvisioning(type, config.activeDataSubId); } else { - runSilentTetherProvisioning(type, config.subId); + runSilentTetherProvisioning(type, config.activeDataSubId); } mNeedReRunProvisioningUi = false; } else { @@ -212,7 +208,7 @@ public class EntitlementManager { /** * Tell EntitlementManager that a given type of tethering has been disabled * - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} */ public void stopProvisioningIfNeeded(int type) { mHandler.sendMessage(mHandler.obtainMessage(EVENT_STOP_PROVISIONING, type, 0)); @@ -270,9 +266,9 @@ public class EntitlementManager { if (mCellularPermitted.indexOfKey(downstream) < 0) { if (mNeedReRunProvisioningUi) { mNeedReRunProvisioningUi = false; - runUiTetherProvisioning(downstream, config.subId); + runUiTetherProvisioning(downstream, config.activeDataSubId); } else { - runSilentTetherProvisioning(downstream, config.subId); + runSilentTetherProvisioning(downstream, config.activeDataSubId); } } } @@ -298,7 +294,7 @@ public class EntitlementManager { /** * Re-check tethering provisioning for all enabled tether types. - * Reference ConnectivityManager.TETHERING_{@code *} for each tether type. + * Reference TetheringManager.TETHERING_{@code *} for each tether type. * * @param config an object that encapsulates the various tethering configuration elements. * Note: this method is only called from TetherMaster on the handler thread. @@ -336,7 +332,8 @@ public class EntitlementManager { .getSystemService(Context.CARRIER_CONFIG_SERVICE); if (configManager == null) return null; - final PersistableBundle carrierConfig = configManager.getConfigForSubId(config.subId); + final PersistableBundle carrierConfig = configManager.getConfigForSubId( + config.activeDataSubId); if (CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) { return carrierConfig; @@ -364,7 +361,7 @@ public class EntitlementManager { /** * Run no UI tethering provisioning check. - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} * @param subId default data subscription ID. */ @VisibleForTesting @@ -378,13 +375,10 @@ public class EntitlementManager { intent.putExtra(EXTRA_RUN_PROVISION, true); intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); intent.putExtra(EXTRA_SUBID, subId); - intent.setComponent(TETHER_SERVICE); - final long ident = Binder.clearCallingIdentity(); - try { - mContext.startServiceAsUser(intent, UserHandle.CURRENT); - } finally { - Binder.restoreCallingIdentity(ident); - } + intent.setComponent(mSilentProvisioningService); + // Only admin user can change tethering and SilentTetherProvisioning don't need to + // show UI, it is fine to always start setting's background service as system user. + mContext.startService(intent); } private void runUiTetherProvisioning(int type, int subId) { @@ -394,7 +388,7 @@ public class EntitlementManager { /** * Run the UI-enabled tethering provisioning check. - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} * @param subId default data subscription ID. * @param receiver to receive entitlement check result. */ @@ -402,17 +396,14 @@ public class EntitlementManager { protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) { if (DBG) mLog.i("runUiTetherProvisioning: " + type); - Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING); + Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING_UI); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); intent.putExtra(EXTRA_SUBID, subId); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - final long ident = Binder.clearCallingIdentity(); - try { - mContext.startActivityAsUser(intent, UserHandle.CURRENT); - } finally { - Binder.restoreCallingIdentity(ident); - } + // Only launch entitlement UI for system user. Entitlement UI should not appear for other + // user because only admin user is allowed to change tethering. + mContext.startActivity(intent); } // Not needed to check if this don't run on the handler thread because it's private. @@ -468,7 +459,7 @@ public class EntitlementManager { * Add the mapping between provisioning result and tethering type. * Notify UpstreamNetworkMonitor if Cellular permission changes. * - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} * @param resultCode Provisioning result */ protected void addDownstreamMapping(int type, int resultCode) { @@ -483,7 +474,7 @@ public class EntitlementManager { /** * Remove the mapping for input tethering type. - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} */ protected void removeDownstreamMapping(int type) { mLog.i("removeDownstreamMapping: " + type); @@ -632,7 +623,7 @@ public class EntitlementManager { /** * Update the last entitlement value to internal cache * - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} * @param resultCode last entitlement value * @return the last updated entitlement value */ @@ -671,7 +662,7 @@ public class EntitlementManager { receiver.send(cacheValue, null); } else { ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver); - runUiTetherProvisioning(downstream, config.subId, proxy); + runUiTetherProvisioning(downstream, config.activeDataSubId, proxy); } } } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java index 93054140213d..66b9ade81019 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java @@ -29,6 +29,7 @@ import android.util.Log; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; @@ -257,7 +258,7 @@ public class IPv6TetheringCoordinator { final LinkProperties lp = new LinkProperties(); final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48); - lp.addRoute(new RouteInfo(local48, null, null)); + lp.addRoute(new RouteInfo(local48, null, null, RouteInfo.RTN_UNICAST)); final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64); // Because this is a locally-generated ULA, we don't have an upstream @@ -273,7 +274,13 @@ public class IPv6TetheringCoordinator { final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length); bytes[7] = (byte) (subnetId >> 8); bytes[8] = (byte) subnetId; - return new IpPrefix(bytes, prefixlen); + final InetAddress addr; + try { + addr = InetAddress.getByAddress(bytes); + } catch (UnknownHostException e) { + throw new IllegalStateException("Invalid address length: " + bytes.length, e); + } + return new IpPrefix(addr, prefixlen); } // Generates a Unique Locally-assigned Prefix: diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java index 16734d83e3aa..cc36f4a9c516 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java @@ -16,35 +16,40 @@ package com.android.server.connectivity.tethering; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.STATS_PER_UID; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.UID_TETHERING; +import static android.net.NetworkStats.UID_TETHERING; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.usage.NetworkStatsManager; import android.content.ContentResolver; -import android.net.ITetheringStatsProvider; +import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkStats; +import android.net.NetworkStats.Entry; import android.net.RouteInfo; import android.net.netlink.ConntrackMessage; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkSocket; -import android.net.util.IpUtils; +import android.net.netstats.provider.AbstractNetworkStatsProvider; +import android.net.netstats.provider.NetworkStatsProviderCallback; import android.net.util.SharedLog; import android.os.Handler; -import android.os.INetworkManagementService; -import android.os.Looper; -import android.os.RemoteException; -import android.os.SystemClock; import android.provider.Settings; import android.system.ErrnoException; import android.system.OsConstants; import android.text.TextUtils; +import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; @@ -73,13 +78,19 @@ public class OffloadController { private static final String ANYIP = "0.0.0.0"; private static final ForwardedStats EMPTY_STATS = new ForwardedStats(); + @VisibleForTesting + enum StatsType { + STATS_PER_IFACE, + STATS_PER_UID, + } + private enum UpdateType { IF_NEEDED, FORCE }; private final Handler mHandler; private final OffloadHardwareInterface mHwInterface; private final ContentResolver mContentResolver; - private final INetworkManagementService mNms; - private final ITetheringStatsProvider mStatsProvider; + private final @NonNull OffloadTetheringStatsProvider mStatsProvider; + private final @Nullable NetworkStatsProviderCallback mStatsProviderCb; private final SharedLog mLog; private final HashMap<String, LinkProperties> mDownstreams; private boolean mConfigInitialized; @@ -109,22 +120,23 @@ public class OffloadController { private int mNatUpdateNetlinkErrors; public OffloadController(Handler h, OffloadHardwareInterface hwi, - ContentResolver contentResolver, INetworkManagementService nms, SharedLog log) { + ContentResolver contentResolver, NetworkStatsManager nsm, SharedLog log) { mHandler = h; mHwInterface = hwi; mContentResolver = contentResolver; - mNms = nms; mStatsProvider = new OffloadTetheringStatsProvider(); mLog = log.forSubComponent(TAG); mDownstreams = new HashMap<>(); mExemptPrefixes = new HashSet<>(); mLastLocalPrefixStrs = new HashSet<>(); - + NetworkStatsProviderCallback providerCallback = null; try { - mNms.registerTetheringStatsProvider(mStatsProvider, getClass().getSimpleName()); - } catch (RemoteException e) { - mLog.e("Cannot register offload stats provider: " + e); + providerCallback = nsm.registerNetworkStatsProvider( + getClass().getSimpleName(), mStatsProvider); + } catch (RuntimeException e) { + Log.wtf(TAG, "Cannot register offload stats provider: " + e); } + mStatsProviderCb = providerCallback; } /** Start hardware offload. */ @@ -173,7 +185,7 @@ public class OffloadController { // and we need to synchronize stats and limits between // software and hardware forwarding. updateStatsForAllUpstreams(); - forceTetherStatsPoll(); + mStatsProvider.pushTetherStats(); } @Override @@ -186,7 +198,7 @@ public class OffloadController { // limits set take into account any software tethering // traffic that has been happening in the meantime. updateStatsForAllUpstreams(); - forceTetherStatsPoll(); + mStatsProvider.pushTetherStats(); // [2] (Re)Push all state. computeAndPushLocalPrefixes(UpdateType.FORCE); pushAllDownstreamState(); @@ -204,14 +216,11 @@ public class OffloadController { // the HAL queued the callback. // TODO: rev the HAL so that it provides an interface name. - // Fetch current stats, so that when our notification reaches - // NetworkStatsService and triggers a poll, we will respond with - // current data (which will be above the limit that was reached). - // Note that if we just changed upstream, this is unnecessary but harmless. - // The stats for the previous upstream were already updated on this thread - // just after the upstream was changed, so they are also up-to-date. updateStatsForCurrentUpstream(); - forceTetherStatsPoll(); + mStatsProvider.pushTetherStats(); + // Push stats to service does not cause the service react to it immediately. + // Inform the service about limit reached. + if (mStatsProviderCb != null) mStatsProviderCb.onLimitReached(); } @Override @@ -253,42 +262,37 @@ public class OffloadController { return mConfigInitialized && mControlInitialized; } - private class OffloadTetheringStatsProvider extends ITetheringStatsProvider.Stub { - @Override - public NetworkStats getTetherStats(int how) { - // getTetherStats() is the only function in OffloadController that can be called from - // a different thread. Do not attempt to update stats by querying the offload HAL - // synchronously from a different thread than our Handler thread. http://b/64771555. - Runnable updateStats = () -> { - updateStatsForCurrentUpstream(); - }; - if (Looper.myLooper() == mHandler.getLooper()) { - updateStats.run(); - } else { - mHandler.post(updateStats); - } - - NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0); - NetworkStats.Entry entry = new NetworkStats.Entry(); - entry.set = SET_DEFAULT; - entry.tag = TAG_NONE; - entry.uid = (how == STATS_PER_UID) ? UID_TETHERING : UID_ALL; - - for (Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) { - ForwardedStats value = kv.getValue(); - entry.iface = kv.getKey(); - entry.rxBytes = value.rxBytes; - entry.txBytes = value.txBytes; - stats.addValues(entry); + @VisibleForTesting + class OffloadTetheringStatsProvider extends AbstractNetworkStatsProvider { + // These stats must only ever be touched on the handler thread. + @NonNull + private NetworkStats mIfaceStats = new NetworkStats(0L, 0); + @NonNull + private NetworkStats mUidStats = new NetworkStats(0L, 0); + + @VisibleForTesting + @NonNull + NetworkStats getTetherStats(@NonNull StatsType how) { + NetworkStats stats = new NetworkStats(0L, 0); + final int uid = (how == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL; + + for (final Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) { + final ForwardedStats value = kv.getValue(); + final Entry entry = new Entry(kv.getKey(), uid, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, value.rxBytes, 0L, value.txBytes, 0L, 0L); + stats = stats.addValues(entry); } return stats; } @Override - public void setInterfaceQuota(String iface, long quotaBytes) { + public void setLimit(String iface, long quotaBytes) { + mLog.i("setLimit: " + iface + "," + quotaBytes); + // Listen for all iface is necessary since upstream might be changed after limit + // is set. mHandler.post(() -> { - if (quotaBytes == ITetheringStatsProvider.QUOTA_UNLIMITED) { + if (quotaBytes == QUOTA_UNLIMITED) { mInterfaceQuotas.remove(iface); } else { mInterfaceQuotas.put(iface, quotaBytes); @@ -296,6 +300,42 @@ public class OffloadController { maybeUpdateDataLimit(iface); }); } + + /** + * Push stats to service, but does not cause a force polling. Note that this can only be + * called on the handler thread. + */ + public void pushTetherStats() { + // TODO: remove the accumulated stats and report the diff from HAL directly. + if (null == mStatsProviderCb) return; + final NetworkStats ifaceDiff = + getTetherStats(StatsType.STATS_PER_IFACE).subtract(mIfaceStats); + final NetworkStats uidDiff = + getTetherStats(StatsType.STATS_PER_UID).subtract(mUidStats); + try { + mStatsProviderCb.onStatsUpdated(0 /* token */, ifaceDiff, uidDiff); + mIfaceStats = mIfaceStats.add(ifaceDiff); + mUidStats = mUidStats.add(uidDiff); + } catch (RuntimeException e) { + mLog.e("Cannot report network stats: ", e); + } + } + + @Override + public void requestStatsUpdate(int token) { + mLog.i("requestStatsUpdate: " + token); + // Do not attempt to update stats by querying the offload HAL + // synchronously from a different thread than the Handler thread. http://b/64771555. + mHandler.post(() -> { + updateStatsForCurrentUpstream(); + pushTetherStats(); + }); + } + + @Override + public void setAlert(long quotaBytes) { + // TODO: Ask offload HAL to notify alert without stopping traffic. + } } private String currentUpstreamInterface() { @@ -353,14 +393,6 @@ public class OffloadController { } } - private void forceTetherStatsPoll() { - try { - mNms.tetherLimitReached(mStatsProvider); - } catch (RemoteException e) { - mLog.e("Cannot report data limit reached: " + e); - } - } - /** Set current tethering upstream LinkProperties. */ public void setUpstreamLinkProperties(LinkProperties lp) { if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return; @@ -477,9 +509,10 @@ public class OffloadController { if (!ri.hasGateway()) continue; final String gateway = ri.getGateway().getHostAddress(); - if (ri.isIPv4Default()) { + final InetAddress address = ri.getDestination().getAddress(); + if (ri.isDefaultRoute() && address instanceof Inet4Address) { v4gateway = gateway; - } else if (ri.isIPv6Default()) { + } else if (ri.isDefaultRoute() && address instanceof Inet6Address) { v6gateways.add(gateway); } } @@ -547,7 +580,10 @@ public class OffloadController { private static boolean shouldIgnoreDownstreamRoute(RouteInfo route) { // Ignore any link-local routes. - if (!route.getDestinationLinkAddress().isGlobalPreferred()) return true; + final IpPrefix destination = route.getDestination(); + final LinkAddress linkAddr = new LinkAddress(destination.getAddress(), + destination.getPrefixLength()); + if (!linkAddr.isGlobalPreferred()) return true; return false; } @@ -588,7 +624,7 @@ public class OffloadController { return; } - if (!IpUtils.isValidUdpOrTcpPort(srcPort)) { + if (!isValidUdpOrTcpPort(srcPort)) { mLog.e("Invalid src port: " + srcPort); return; } @@ -599,7 +635,7 @@ public class OffloadController { return; } - if (!IpUtils.isValidUdpOrTcpPort(dstPort)) { + if (!isValidUdpOrTcpPort(dstPort)) { mLog.e("Invalid dst port: " + dstPort); return; } @@ -628,7 +664,7 @@ public class OffloadController { private static Inet4Address parseIPv4Address(String addrString) { try { - final InetAddress ip = InetAddress.parseNumericAddress(addrString); + final InetAddress ip = InetAddresses.parseNumericAddress(addrString); // TODO: Consider other sanitization steps here, including perhaps: // not eql to 0.0.0.0 // not within 169.254.0.0/16 @@ -668,4 +704,8 @@ public class OffloadController { return 180; } } + + private static boolean isValidUdpOrTcpPort(int port) { + return port > 0 && port < 65536; + } } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java index 00a677338b1b..90b9d3f148dc 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java @@ -16,7 +16,7 @@ package com.android.server.connectivity.tethering; -import static com.android.internal.util.BitUtils.uint16; +import static android.net.util.TetheringUtils.uint16; import android.hardware.tetheroffload.control.V1_0.IOffloadControl; import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; @@ -24,10 +24,13 @@ import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; import android.net.util.SharedLog; +import android.net.util.TetheringUtils; import android.os.Handler; import android.os.RemoteException; import android.system.OsConstants; +import com.android.internal.annotations.VisibleForTesting; + import java.util.ArrayList; @@ -47,8 +50,6 @@ public class OffloadHardwareInterface { private static final String NO_IPV4_ADDRESS = ""; private static final String NO_IPV4_GATEWAY = ""; - private static native boolean configOffload(); - private final Handler mHandler; private final SharedLog mLog; private IOffloadControl mOffloadControl; @@ -92,6 +93,12 @@ public class OffloadHardwareInterface { txBytes = 0; } + @VisibleForTesting + public ForwardedStats(long rxBytes, long txBytes) { + this.rxBytes = rxBytes; + this.txBytes = txBytes; + } + /** Add Tx/Rx bytes. */ public void add(ForwardedStats other) { rxBytes += other.rxBytes; @@ -107,8 +114,6 @@ public class OffloadHardwareInterface { public OffloadHardwareInterface(Handler h, SharedLog log) { mHandler = h; mLog = log.forSubComponent(TAG); - - System.loadLibrary("tetheroffloadjni"); } /** Get default value indicating whether offload is supported. */ @@ -118,7 +123,7 @@ public class OffloadHardwareInterface { /** Configure offload management process. */ public boolean initOffloadConfig() { - return configOffload(); + return TetheringUtils.configOffload(); } /** Initialize the tethering offload HAL. */ diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 3116321e0954..5bf41ce25b2b 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -20,23 +20,25 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; -import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; -import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY; -import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER; -import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER; -import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER; import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_INVALID; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHERING_WIFI_P2P; -import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL; -import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE; -import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; +import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; +import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; +import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER; +import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER; +import static android.net.TetheringManager.EXTRA_ERRORED_TETHER; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_INVALID; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHER_ERROR_MASTER_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; +import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE; +import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; +import static android.net.util.TetheringMessageBase.BASE_MASTER; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -49,8 +51,10 @@ import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANG import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.app.Notification; +import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; @@ -61,19 +65,18 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.hardware.usb.UsbManager; +import android.net.ConnectivityManager; import android.net.INetd; -import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; import android.net.ITetheringEventCallback; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkInfo; -import android.net.NetworkUtils; import android.net.TetherStatesParcel; import android.net.TetheringConfigurationParcel; import android.net.ip.IpServer; +import android.net.shared.NetdUtils; import android.net.util.BaseNetdUnsolicitedEventListener; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; @@ -86,12 +89,12 @@ import android.net.wifi.p2p.WifiP2pManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ServiceSpecificException; import android.os.UserHandle; import android.os.UserManager; import android.telephony.PhoneStateListener; @@ -101,12 +104,12 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; -import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; -import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.networkstack.tethering.R; @@ -120,6 +123,8 @@ import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; /** * @@ -137,6 +142,8 @@ public class Tethering { }; private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(sMessageClasses); + // Keep in sync with NETID_UNSET in system/netd/include/netid_client.h + private static final int NETID_UNSET = 0; private static class TetherState { public final IpServer ipServer; @@ -170,10 +177,6 @@ public class Tethering { private final Context mContext; private final ArrayMap<String, TetherState> mTetherStates; private final BroadcastReceiver mStateReceiver; - // Stopship: replace mNMService before production. - private final INetworkManagementService mNMService; - private final INetworkStatsService mStatsService; - private final INetworkPolicyManager mPolicyManager; private final Looper mLooper; private final StateMachine mTetherMasterSM; private final OffloadController mOffloadController; @@ -185,10 +188,10 @@ public class Tethering { private final TetheringDependencies mDeps; private final EntitlementManager mEntitlementMgr; private final Handler mHandler; - private final PhoneStateListener mPhoneStateListener; private final INetd mNetd; private final NetdCallback mNetdCallback; private final UserRestrictionActionListener mTetheringRestriction; + private final ActiveDataSubIdListener mActiveDataSubIdListener; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; // All the usage of mTetheringEventCallback should run in the same thread. private ITetheringEventCallback mTetheringEventCallback = null; @@ -203,14 +206,13 @@ public class Tethering { private boolean mWifiTetherRequested; private Network mTetherUpstream; private TetherStatesParcel mTetherStatesParcel; + private boolean mDataSaverEnabled = false; + private String mWifiP2pTetherInterface = null; public Tethering(TetheringDependencies deps) { mLog.mark("Tethering.constructed"); mDeps = deps; mContext = mDeps.getContext(); - mNMService = mDeps.getINetworkManagementService(); - mStatsService = mDeps.getINetworkStatsService(); - mPolicyManager = mDeps.getINetworkPolicyManager(); mNetd = mDeps.getINetd(mContext); mLooper = mDeps.getTetheringLooper(); @@ -221,12 +223,13 @@ public class Tethering { mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps); mTetherMasterSM.start(); + final NetworkStatsManager statsManager = + (NetworkStatsManager) mContext.getSystemService(Context.NETWORK_STATS_SERVICE); mHandler = mTetherMasterSM.getHandler(); mOffloadController = new OffloadController(mHandler, - mDeps.getOffloadHardwareInterface(mHandler, mLog), - mContext.getContentResolver(), mNMService, - mLog); - mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, + mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(), + statsManager, mLog); + mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new HashSet<>(); @@ -252,26 +255,6 @@ public class Tethering { mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); }); - mPhoneStateListener = new PhoneStateListener(mLooper) { - @Override - public void onActiveDataSubscriptionIdChanged(int subId) { - mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId - + " to " + subId); - if (subId == mActiveDataSubId) return; - - mActiveDataSubId = subId; - updateConfiguration(); - // To avoid launching unexpected provisioning checks, ignore re-provisioning when - // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be - // triggered again when CarrierConfig is loaded. - if (mEntitlementMgr.getCarrierConfig(mConfig) != null) { - mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); - } else { - mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded"); - } - } - }; - mStateReceiver = new StateReceiver(); mNetdCallback = new NetdCallback(); @@ -282,8 +265,10 @@ public class Tethering { } final UserManager userManager = (UserManager) mContext.getSystemService( - Context.USER_SERVICE); + Context.USER_SERVICE); mTetheringRestriction = new UserRestrictionActionListener(userManager, this); + final TetheringThreadExecutor executor = new TetheringThreadExecutor(mHandler); + mActiveDataSubIdListener = new ActiveDataSubIdListener(executor); // Load tethering configuration. updateConfiguration(); @@ -294,8 +279,8 @@ public class Tethering { private void startStateMachineUpdaters(Handler handler) { mCarrierConfigChange.startListening(); - mContext.getSystemService(TelephonyManager.class).listen( - mPhoneStateListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); + mContext.getSystemService(TelephonyManager.class).listen(mActiveDataSubIdListener, + PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_STATE); @@ -304,14 +289,45 @@ public class Tethering { filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED); + filter.addAction(ACTION_RESTRICT_BACKGROUND_CHANGED); mContext.registerReceiver(mStateReceiver, filter, null, handler); + } - filter = new IntentFilter(); - filter.addAction(Intent.ACTION_MEDIA_SHARED); - filter.addAction(Intent.ACTION_MEDIA_UNSHARED); - filter.addDataScheme("file"); - mContext.registerReceiver(mStateReceiver, filter, null, handler); + private class TetheringThreadExecutor implements Executor { + private final Handler mTetherHandler; + TetheringThreadExecutor(Handler handler) { + mTetherHandler = handler; + } + @Override + public void execute(Runnable command) { + if (!mTetherHandler.post(command)) { + throw new RejectedExecutionException(mTetherHandler + " is shutting down"); + } + } + } + private class ActiveDataSubIdListener extends PhoneStateListener { + ActiveDataSubIdListener(Executor executor) { + super(executor); + } + + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId + + " to " + subId); + if (subId == mActiveDataSubId) return; + + mActiveDataSubId = subId; + updateConfiguration(); + // To avoid launching unexpected provisioning checks, ignore re-provisioning + // when no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() + // ill be triggered again when CarrierConfig is loaded. + if (mEntitlementMgr.getCarrierConfig(mConfig) != null) { + mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); + } else { + mLog.log("IGNORED reevaluate provisioning, no carrier config loaded"); + } + } } private WifiManager getWifiManager() { @@ -326,8 +342,7 @@ public class Tethering { } private void maybeDunSettingChanged() { - final boolean isDunRequired = TetheringConfiguration.checkDunRequired( - mContext, mActiveDataSubId); + final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext); if (isDunRequired == mConfig.isDunRequired) return; updateConfiguration(); } @@ -401,7 +416,6 @@ public class Tethering { } } - void interfaceRemoved(String iface) { if (VDBG) Log.d(TAG, "interfaceRemoved " + iface); synchronized (mPublicSync) { @@ -472,7 +486,7 @@ public class Tethering { } private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) { - final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + final BluetoothAdapter adapter = mDeps.getBluetoothAdapter(); if (adapter == null || !adapter.isEnabled()) { Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " + (adapter == null)); @@ -633,8 +647,7 @@ public class Tethering { reportTetherStateChanged(mTetherStatesParcel); final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED); - bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING - | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList); bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList); bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList); @@ -651,19 +664,19 @@ public class Tethering { if (usbTethered) { if (wifiTethered || bluetoothTethered) { - showTetheredNotification(SystemMessage.NOTE_TETHER_GENERAL); + showTetheredNotification(R.drawable.stat_sys_tether_general); } else { - showTetheredNotification(SystemMessage.NOTE_TETHER_USB); + showTetheredNotification(R.drawable.stat_sys_tether_usb); } } else if (wifiTethered) { if (bluetoothTethered) { - showTetheredNotification(SystemMessage.NOTE_TETHER_GENERAL); + showTetheredNotification(R.drawable.stat_sys_tether_general); } else { /* We now have a status bar icon for WifiTethering, so drop the notification */ clearTetheredNotification(); } } else if (bluetoothTethered) { - showTetheredNotification(SystemMessage.NOTE_TETHER_BLUETOOTH); + showTetheredNotification(R.drawable.stat_sys_tether_bluetooth); } else { clearTetheredNotification(); } @@ -676,30 +689,22 @@ public class Tethering { @VisibleForTesting protected void showTetheredNotification(int id, boolean tetheringOn) { NotificationManager notificationManager = - (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + (NotificationManager) mContext.createContextAsUser(UserHandle.ALL, 0) + .getSystemService(Context.NOTIFICATION_SERVICE); if (notificationManager == null) { return; } - int icon = 0; - switch(id) { - case SystemMessage.NOTE_TETHER_USB: - icon = R.drawable.stat_sys_tether_usb; - break; - case SystemMessage.NOTE_TETHER_BLUETOOTH: - icon = R.drawable.stat_sys_tether_bluetooth; - break; - case SystemMessage.NOTE_TETHER_GENERAL: - default: - icon = R.drawable.stat_sys_tether_general; - break; - } + final NotificationChannel channel = new NotificationChannel( + "TETHERING_STATUS", + mContext.getResources().getString(R.string.notification_channel_tethering_status), + NotificationManager.IMPORTANCE_LOW); + notificationManager.createNotificationChannel(channel); if (mLastNotificationId != 0) { - if (mLastNotificationId == icon) { + if (mLastNotificationId == id) { return; } - notificationManager.cancelAsUser(null, mLastNotificationId, - UserHandle.ALL); + notificationManager.cancel(null, mLastNotificationId); mLastNotificationId = 0; } @@ -707,8 +712,8 @@ public class Tethering { intent.setClassName("com.android.settings", "com.android.settings.TetherSettings"); intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0, - null, UserHandle.CURRENT); + PendingIntent pi = PendingIntent.getActivity( + mContext.createContextAsUser(UserHandle.CURRENT, 0), 0, intent, 0, null); Resources r = mContext.getResources(); final CharSequence title; @@ -723,32 +728,30 @@ public class Tethering { } if (mTetheredNotificationBuilder == null) { - mTetheredNotificationBuilder = new Notification.Builder(mContext, - SystemNotificationChannels.NETWORK_STATUS); + mTetheredNotificationBuilder = new Notification.Builder(mContext, channel.getId()); mTetheredNotificationBuilder.setWhen(0) .setOngoing(true) .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)) + android.R.color.system_notification_accent_color)) .setVisibility(Notification.VISIBILITY_PUBLIC) .setCategory(Notification.CATEGORY_STATUS); } - mTetheredNotificationBuilder.setSmallIcon(icon) + mTetheredNotificationBuilder.setSmallIcon(id) .setContentTitle(title) .setContentText(message) .setContentIntent(pi); mLastNotificationId = id; - notificationManager.notifyAsUser(null, mLastNotificationId, - mTetheredNotificationBuilder.buildInto(new Notification()), UserHandle.ALL); + notificationManager.notify(null, mLastNotificationId, mTetheredNotificationBuilder.build()); } @VisibleForTesting protected void clearTetheredNotification() { NotificationManager notificationManager = - (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + (NotificationManager) mContext.createContextAsUser(UserHandle.ALL, 0) + .getSystemService(Context.NOTIFICATION_SERVICE); if (notificationManager != null && mLastNotificationId != 0) { - notificationManager.cancelAsUser(null, mLastNotificationId, - UserHandle.ALL); + notificationManager.cancel(null, mLastNotificationId); mLastNotificationId = 0; } } @@ -773,6 +776,9 @@ public class Tethering { } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) { mLog.log("OBSERVED user restrictions changed"); handleUserRestrictionAction(); + } else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED)) { + mLog.log("OBSERVED data saver changed"); + handleDataSaverChanged(); } } @@ -847,6 +853,11 @@ public class Tethering { } } + private boolean isGroupOwner(WifiP2pGroup group) { + return group != null && group.isGroupOwner() + && !TextUtils.isEmpty(group.getInterface()); + } + private void handleWifiP2pAction(Intent intent) { if (mConfig.isWifiP2pLegacyTetheringMode()) return; @@ -859,30 +870,51 @@ public class Tethering { Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group); } - if (p2pInfo == null) return; - // When a p2p group is disconnected, p2pInfo would be cleared. - // group is still valid for detecting whether this device is group owner. - if (group == null || !group.isGroupOwner() - || TextUtils.isEmpty(group.getInterface())) return; - synchronized (Tethering.this.mPublicSync) { - // Enter below only if this device is Group Owner with a valid interface. - if (p2pInfo.groupFormed) { - TetherState tetherState = mTetherStates.get(group.getInterface()); - if (tetherState == null - || (tetherState.lastState != IpServer.STATE_TETHERED - && tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) { - enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY); - } - } else { - disableWifiP2pIpServingLocked(group.getInterface()); + // if no group is formed, bring it down if needed. + if (p2pInfo == null || !p2pInfo.groupFormed) { + disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface); + mWifiP2pTetherInterface = null; + return; } + + // If there is a group but the device is not the owner, bail out. + if (!isGroupOwner(group)) return; + + // If already serving from the correct interface, nothing to do. + if (group.getInterface().equals(mWifiP2pTetherInterface)) return; + + // If already serving from another interface, turn it down first. + if (!TextUtils.isEmpty(mWifiP2pTetherInterface)) { + mLog.w("P2P tethered interface " + mWifiP2pTetherInterface + + "is different from current interface " + + group.getInterface() + ", re-tether it"); + disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface); + } + + // Finally bring up serving on the new interface + mWifiP2pTetherInterface = group.getInterface(); + enableWifiIpServingLocked(mWifiP2pTetherInterface, IFACE_IP_MODE_LOCAL_ONLY); } } private void handleUserRestrictionAction() { mTetheringRestriction.onUserRestrictionsChanged(); } + + private void handleDataSaverChanged() { + final ConnectivityManager connMgr = (ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + final boolean isDataSaverEnabled = connMgr.getRestrictBackgroundStatus() + != ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; + + if (mDataSaverEnabled == isDataSaverEnabled) return; + + mDataSaverEnabled = isDataSaverEnabled; + if (mDataSaverEnabled) { + untetherAll(); + } + } } @VisibleForTesting @@ -960,7 +992,9 @@ public class Tethering { disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState); } - private void disableWifiP2pIpServingLocked(String ifname) { + private void disableWifiP2pIpServingLockedIfNeeded(String ifname) { + if (TextUtils.isEmpty(ifname)) return; + disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0); } @@ -1003,8 +1037,8 @@ public class Tethering { String[] ifaces = null; try { - ifaces = mNMService.listInterfaces(); - } catch (Exception e) { + ifaces = mNetd.interfaceGetList(); + } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Error listing Interfaces", e); return; } @@ -1163,7 +1197,6 @@ public class Tethering { } class TetherMasterSM extends StateMachine { - private static final int BASE_MASTER = Protocol.BASE_TETHERING; // an interface SM has requested Tethering/Local Hotspot static final int EVENT_IFACE_SERVING_STATE_ACTIVE = BASE_MASTER + 1; // an interface SM has unrequested Tethering/Local Hotspot @@ -1180,7 +1213,6 @@ public class Tethering { static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7; // Events from EntitlementManager to choose upstream again. static final int EVENT_UPSTREAM_PERMISSION_CHANGED = BASE_MASTER + 8; - private final State mInitialState; private final State mTetherModeAliveState; @@ -1265,25 +1297,25 @@ public class Tethering { protected boolean turnOnMasterTetherSettings() { final TetheringConfiguration cfg = mConfig; try { - mNMService.setIpForwardingEnabled(true); - } catch (Exception e) { + mNetd.ipfwdEnableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { mLog.e(e); transitionTo(mSetIpForwardingEnabledErrorState); return false; } + // TODO: Randomize DHCPv4 ranges, especially in hotspot mode. // Legacy DHCP server is disabled if passed an empty ranges array final String[] dhcpRanges = cfg.enableLegacyDhcpServer - ? cfg.legacyDhcpRanges - : new String[0]; + ? cfg.legacyDhcpRanges : new String[0]; try { - // TODO: Find a more accurate method name (startDHCPv4()?). - mNMService.startTethering(dhcpRanges); - } catch (Exception e) { + NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges); + } catch (RemoteException | ServiceSpecificException e) { try { - mNMService.stopTethering(); - mNMService.startTethering(dhcpRanges); - } catch (Exception ee) { + // Stop and retry. + mNetd.tetherStop(); + NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges); + } catch (RemoteException | ServiceSpecificException ee) { mLog.e(ee); transitionTo(mStartTetheringErrorState); return false; @@ -1295,15 +1327,15 @@ public class Tethering { protected boolean turnOffMasterTetherSettings() { try { - mNMService.stopTethering(); - } catch (Exception e) { + mNetd.tetherStop(); + } catch (RemoteException | ServiceSpecificException e) { mLog.e(e); transitionTo(mStopTetheringErrorState); return false; } try { - mNMService.setIpForwardingEnabled(false); - } catch (Exception e) { + mNetd.ipfwdDisableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { mLog.e(e); transitionTo(mSetIpForwardingDisabledErrorState); return false; @@ -1366,19 +1398,25 @@ public class Tethering { protected void setDnsForwarders(final Network network, final LinkProperties lp) { // TODO: Set v4 and/or v6 DNS per available connectivity. - String[] dnsServers = mConfig.defaultIPv4DNS; final Collection<InetAddress> dnses = lp.getDnsServers(); // TODO: Properly support the absence of DNS servers. + final String[] dnsServers; if (dnses != null && !dnses.isEmpty()) { - // TODO: remove this invocation of NetworkUtils.makeStrings(). - dnsServers = NetworkUtils.makeStrings(dnses); + dnsServers = new String[dnses.size()]; + int i = 0; + for (InetAddress dns : dnses) { + dnsServers[i++] = dns.getHostAddress(); + } + } else { + dnsServers = mConfig.defaultIPv4DNS; } + final int netId = (network != null) ? network.netId : NETID_UNSET; try { - mNMService.setDnsForwarders(network, dnsServers); + mNetd.tetherDnsSet(netId, dnsServers); mLog.log(String.format( "SET DNS forwarders: network=%s dnsServers=%s", network, Arrays.toString(dnsServers))); - } catch (Exception e) { + } catch (RemoteException | ServiceSpecificException e) { // TODO: Investigate how this can fail and what exactly // happens if/when such failures occur. mLog.e("setting DNS forwarders failed, " + e); @@ -1681,8 +1719,8 @@ public class Tethering { Log.e(TAG, "Error in startTethering"); notify(IpServer.CMD_START_TETHERING_ERROR); try { - mNMService.setIpForwardingEnabled(false); - } catch (Exception e) { } + mNetd.ipfwdDisableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { } } } @@ -1692,8 +1730,8 @@ public class Tethering { Log.e(TAG, "Error in stopTethering"); notify(IpServer.CMD_STOP_TETHERING_ERROR); try { - mNMService.setIpForwardingEnabled(false); - } catch (Exception e) { } + mNetd.ipfwdDisableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { } } } @@ -1703,11 +1741,11 @@ public class Tethering { Log.e(TAG, "Error in setDnsForwarders"); notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR); try { - mNMService.stopTethering(); - } catch (Exception e) { } + mNetd.tetherStop(); + } catch (RemoteException | ServiceSpecificException e) { } try { - mNMService.setIpForwardingEnabled(false); - } catch (Exception e) { } + mNetd.ipfwdDisableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { } } } @@ -1867,7 +1905,7 @@ public class Tethering { } } - void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { // Binder.java closes the resource for us. @SuppressWarnings("resource") final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); @@ -1976,15 +2014,6 @@ public class Tethering { mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error)); - try { - // Notify that we're tethering (or not) this interface. - // This is how data saver for instance knows if the user explicitly - // turned on tethering (thus keeping us from being in data saver mode). - mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED); - } catch (RemoteException e) { - // Not really very much we can do here. - } - // If TetherMasterSM is in ErrorState, TetherMasterSM stays there. // Thus we give a chance for TetherMasterSM to recover to InitialState // by sending CMD_CLEAR_ERROR @@ -2048,7 +2077,7 @@ public class Tethering { mLog.log("adding TetheringInterfaceStateMachine for: " + iface); final TetherState tetherState = new TetherState( - new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService, + new IpServer(iface, mLooper, interfaceType, mLog, mNetd, makeControlCallback(), mConfig.enableLegacyDhcpServer, mDeps.getIpServerDependencies())); mTetherStates.put(iface, tetherState); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java index 0ab4d634e84d..068c346fbfc1 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -21,31 +21,19 @@ import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; -import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; - -import static com.android.internal.R.array.config_mobile_hotspot_provision_app; -import static com.android.internal.R.array.config_tether_bluetooth_regexs; -import static com.android.internal.R.array.config_tether_dhcp_range; -import static com.android.internal.R.array.config_tether_upstream_types; -import static com.android.internal.R.array.config_tether_usb_regexs; -import static com.android.internal.R.array.config_tether_wifi_p2p_regexs; -import static com.android.internal.R.array.config_tether_wifi_regexs; -import static com.android.internal.R.bool.config_tether_upstream_automatic; -import static com.android.internal.R.integer.config_mobile_hotspot_provision_check_period; -import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui; - -import android.content.ContentResolver; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; + import android.content.Context; import android.content.res.Resources; -import android.net.ConnectivityManager; import android.net.TetheringConfigurationParcel; import android.net.util.SharedLog; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.networkstack.tethering.R; import java.io.PrintWriter; import java.util.ArrayList; @@ -85,6 +73,12 @@ public class TetheringConfiguration { private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; + /** + * Use the old dnsmasq DHCP server for tethering instead of the framework implementation. + */ + public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER = + "tether_enable_legacy_dhcp_server"; + public final String[] tetherableUsbRegexs; public final String[] tetherableWifiRegexs; public final String[] tetherableWifiP2pRegexs; @@ -100,35 +94,38 @@ public class TetheringConfiguration { public final String provisioningAppNoUi; public final int provisioningCheckPeriod; - public final int subId; + public final int activeDataSubId; public TetheringConfiguration(Context ctx, SharedLog log, int id) { final SharedLog configLog = log.forSubComponent("config"); - subId = id; - Resources res = getResources(ctx, subId); + activeDataSubId = id; + Resources res = getResources(ctx, activeDataSubId); - tetherableUsbRegexs = getResourceStringArray(res, config_tether_usb_regexs); + tetherableUsbRegexs = getResourceStringArray(res, R.array.config_tether_usb_regexs); // TODO: Evaluate deleting this altogether now that Wi-Fi always passes // us an interface name. Careful consideration needs to be given to // implications for Settings and for provisioning checks. - tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs); - tetherableWifiP2pRegexs = getResourceStringArray(res, config_tether_wifi_p2p_regexs); - tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs); + tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs); + tetherableWifiP2pRegexs = getResourceStringArray( + res, R.array.config_tether_wifi_p2p_regexs); + tetherableBluetoothRegexs = getResourceStringArray( + res, R.array.config_tether_bluetooth_regexs); - isDunRequired = checkDunRequired(ctx, subId); + isDunRequired = checkDunRequired(ctx); - chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic); + chooseUpstreamAutomatically = getResourceBoolean( + res, R.bool.config_tether_upstream_automatic); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); - enableLegacyDhcpServer = getEnableLegacyDhcpServer(ctx); + enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); - provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app); + provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); provisioningAppNoUi = getProvisioningAppNoUi(res); provisioningCheckPeriod = getResourceInteger(res, - config_mobile_hotspot_provision_check_period, + R.integer.config_mobile_hotspot_provision_check_period, 0 /* No periodic re-check */); configLog.log(toString()); @@ -166,8 +163,8 @@ public class TetheringConfiguration { /** Does the dumping.*/ public void dump(PrintWriter pw) { - pw.print("subId: "); - pw.println(subId); + pw.print("activeDataSubId: "); + pw.println(activeDataSubId); dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs); dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs); @@ -179,8 +176,8 @@ public class TetheringConfiguration { pw.print("chooseUpstreamAutomatically: "); pw.println(chooseUpstreamAutomatically); - dumpStringArray(pw, "preferredUpstreamIfaceTypes", - preferredUpstreamNames(preferredUpstreamIfaceTypes)); + pw.print("legacyPreredUpstreamIfaceTypes: "); + pw.println(Arrays.toString(toIntArray(preferredUpstreamIfaceTypes))); dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges); dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS); @@ -196,7 +193,7 @@ public class TetheringConfiguration { /** Returns the string representation of this object.*/ public String toString() { final StringJoiner sj = new StringJoiner(" "); - sj.add(String.format("subId:%d", subId)); + sj.add(String.format("activeDataSubId:%d", activeDataSubId)); sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs))); sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs))); sj.add(String.format("tetherableWifiP2pRegexs:%s", makeString(tetherableWifiP2pRegexs))); @@ -205,7 +202,7 @@ public class TetheringConfiguration { sj.add(String.format("isDunRequired:%s", isDunRequired)); sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically)); sj.add(String.format("preferredUpstreamIfaceTypes:%s", - makeString(preferredUpstreamNames(preferredUpstreamIfaceTypes)))); + toIntArray(preferredUpstreamIfaceTypes))); sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi)); sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer)); @@ -234,29 +231,16 @@ public class TetheringConfiguration { return sj.toString(); } - private static String[] preferredUpstreamNames(Collection<Integer> upstreamTypes) { - String[] upstreamNames = null; - - if (upstreamTypes != null) { - upstreamNames = new String[upstreamTypes.size()]; - int i = 0; - for (Integer netType : upstreamTypes) { - upstreamNames[i] = ConnectivityManager.getNetworkTypeName(netType); - i++; - } - } - - return upstreamNames; - } - /** Check whether dun is required. */ - public static boolean checkDunRequired(Context ctx, int id) { + public static boolean checkDunRequired(Context ctx) { final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); - return (tm != null) ? tm.isTetheringApnRequired(id) : false; + // TelephonyManager would uses the active data subscription, which should be the one used + // by tethering. + return (tm != null) ? tm.isTetheringApnRequired() : false; } private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { - final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types); + final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types); final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); for (int i : ifaceTypes) { switch (i) { @@ -306,7 +290,7 @@ public class TetheringConfiguration { } private static String[] getLegacyDhcpRanges(Resources res) { - final String[] fromResource = getResourceStringArray(res, config_tether_dhcp_range); + final String[] fromResource = getResourceStringArray(res, R.array.config_tether_dhcp_range); if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) { return fromResource; } @@ -315,7 +299,7 @@ public class TetheringConfiguration { private static String getProvisioningAppNoUi(Resources res) { try { - return res.getString(config_mobile_hotspot_provision_app_no_ui); + return res.getString(R.string.config_mobile_hotspot_provision_app_no_ui); } catch (Resources.NotFoundException e) { return ""; } @@ -346,10 +330,14 @@ public class TetheringConfiguration { } } - private static boolean getEnableLegacyDhcpServer(Context ctx) { - final ContentResolver cr = ctx.getContentResolver(); - final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); - return intVal != 0; + private boolean getEnableLegacyDhcpServer(final Resources res) { + return getResourceBoolean(res, R.bool.config_tether_enable_legacy_dhcp_server) + || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER); + } + + @VisibleForTesting + protected boolean getDeviceConfigBoolean(final String name) { + return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, false /** defaultValue */); } private Resources getResources(Context ctx, int subId) { @@ -386,24 +374,28 @@ public class TetheringConfiguration { return false; } + private static int[] toIntArray(Collection<Integer> values) { + final int[] result = new int[values.size()]; + int index = 0; + for (Integer value : values) { + result[index++] = value; + } + return result; + } + /** * Convert this TetheringConfiguration to a TetheringConfigurationParcel. */ public TetheringConfigurationParcel toStableParcelable() { final TetheringConfigurationParcel parcel = new TetheringConfigurationParcel(); - parcel.subId = subId; + parcel.subId = activeDataSubId; parcel.tetherableUsbRegexs = tetherableUsbRegexs; parcel.tetherableWifiRegexs = tetherableWifiRegexs; parcel.tetherableBluetoothRegexs = tetherableBluetoothRegexs; parcel.isDunRequired = isDunRequired; parcel.chooseUpstreamAutomatically = chooseUpstreamAutomatically; - int[] preferredTypes = new int[preferredUpstreamIfaceTypes.size()]; - int index = 0; - for (Integer type : preferredUpstreamIfaceTypes) { - preferredTypes[index++] = type; - } - parcel.preferredUpstreamIfaceTypes = preferredTypes; + parcel.preferredUpstreamIfaceTypes = toIntArray(preferredUpstreamIfaceTypes); parcel.legacyDhcpRanges = legacyDhcpRanges; parcel.defaultIPv4DNS = defaultIPv4DNS; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java index b16b3294a112..e019c3aca26a 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -16,18 +16,15 @@ package com.android.server.connectivity.tethering; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.net.INetd; -import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; import android.net.NetworkRequest; import android.net.ip.IpServer; import android.net.util.SharedLog; import android.os.Handler; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; -import android.os.ServiceManager; import com.android.internal.util.StateMachine; @@ -97,33 +94,6 @@ public abstract class TetheringDependencies { } /** - * Get a reference to INetworkManagementService to registerTetheringStatsProvider from - * OffloadController. Note: This should be removed soon by Usage refactor work in R - * development cycle. - */ - public INetworkManagementService getINetworkManagementService() { - return INetworkManagementService.Stub.asInterface( - ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); - } - - /** - * Get a reference to INetworkStatsService to force update tethering usage. - * Note: This should be removed in R development cycle. - */ - public INetworkStatsService getINetworkStatsService() { - return INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); - } - - /** - * Get a reference to INetworkPolicyManager to be used by tethering. - */ - public INetworkPolicyManager getINetworkPolicyManager() { - return INetworkPolicyManager.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); - } - - /** * Get a reference to INetd to be used by tethering. */ public INetd getINetd(Context context) { @@ -140,4 +110,9 @@ public abstract class TetheringDependencies { * Get Context of TetheringSerice. */ public abstract Context getContext(); + + /** + * Get a reference to BluetoothAdapter to be used by tethering. + */ + public abstract BluetoothAdapter getBluetoothAdapter(); } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java index 6334c20c2acc..d5cdd8a004dc 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java @@ -22,14 +22,17 @@ import android.net.NetworkCapabilities; import android.net.RouteInfo; import android.net.util.InterfaceSet; -import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; /** * @hide */ public final class TetheringInterfaceUtils { + private static final InetAddress IN6ADDR_ANY = getByAddress( + new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + private static final InetAddress INADDR_ANY = getByAddress(new byte[] {0, 0, 0, 0}); + /** * Get upstream interfaces for tethering based on default routes for IPv4/IPv6. * @return null if there is no usable interface, or a set of at least one interface otherwise. @@ -40,7 +43,7 @@ public final class TetheringInterfaceUtils { } final LinkProperties lp = ns.linkProperties; - final String if4 = getInterfaceForDestination(lp, Inet4Address.ANY); + final String if4 = getInterfaceForDestination(lp, INADDR_ANY); final String if6 = getIPv6Interface(ns); return (if4 == null && if6 == null) ? null : new InterfaceSet(if4, if6); @@ -76,7 +79,7 @@ public final class TetheringInterfaceUtils { && ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); return canTether - ? getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY) + ? getInterfaceForDestination(ns.linkProperties, IN6ADDR_ANY) : null; } @@ -86,4 +89,12 @@ public final class TetheringInterfaceUtils { : null; return (ri != null) ? ri.getInterface() : null; } + + private static InetAddress getByAddress(final byte[] addr) { + try { + return InetAddress.getByAddress(null, addr); + } catch (UnknownHostException e) { + throw new AssertionError("illegal address length" + addr.length); + } + } } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java index ba30845e6348..cb7d3920e693 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -21,15 +21,17 @@ import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERM import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED; +import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; import android.app.Service; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; import android.net.IIntResultListener; import android.net.INetworkStackConnector; import android.net.ITetheringConnector; import android.net.ITetheringEventCallback; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; @@ -41,7 +43,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.ResultReceiver; -import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserManager; import android.provider.Settings; @@ -84,6 +85,7 @@ public class TetheringService extends Service { */ @VisibleForTesting public Tethering makeTethering(TetheringDependencies deps) { + System.loadLibrary("tetherutilsjni"); return new Tethering(deps); } @@ -305,9 +307,15 @@ public class TetheringService extends Service { mDeps = new TetheringDependencies() { @Override public NetworkRequest getDefaultNetworkRequest() { - ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - return cm.getDefaultRequest(); + // TODO: b/147280869, add a proper system API to replace this. + final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder() + .clearCapabilities() + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + return trackDefaultRequest; } @Override @@ -339,7 +347,10 @@ public class TetheringService extends Service { service.makeDhcpServer(ifName, params, cb); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + Log.e(TAG, "Fail to make dhcp server"); + try { + cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); + } catch (RemoteException re) { } } } }; @@ -352,7 +363,7 @@ public class TetheringService extends Service { IBinder connector; try { final long before = System.currentTimeMillis(); - while ((connector = ServiceManager.getService( + while ((connector = (IBinder) mContext.getSystemService( Context.NETWORK_STACK_SERVICE)) == null) { if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); @@ -366,6 +377,11 @@ public class TetheringService extends Service { } return INetworkStackConnector.Stub.asInterface(connector); } + + @Override + public BluetoothAdapter getBluetoothAdapter() { + return BluetoothAdapter.getDefaultAdapter(); + } }; } return mDeps; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index dc38c49a0c12..2875f71e5ed2 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -16,11 +16,15 @@ package com.android.server.connectivity.tethering; +import static android.net.ConnectivityManager.TYPE_BLUETOOTH; +import static android.net.ConnectivityManager.TYPE_ETHERNET; +import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; -import static android.net.ConnectivityManager.TYPE_NONE; -import static android.net.ConnectivityManager.getNetworkTypeName; +import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -35,10 +39,11 @@ import android.net.NetworkRequest; import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.os.Handler; -import android.os.Process; import android.util.Log; +import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import com.android.internal.util.StateMachine; import java.util.HashMap; @@ -79,11 +84,25 @@ public class UpstreamNetworkMonitor { public static final int EVENT_ON_LINKPROPERTIES = 2; public static final int EVENT_ON_LOST = 3; public static final int NOTIFY_LOCAL_PREFIXES = 10; + // This value is used by deprecated preferredUpstreamIfaceTypes selection which is default + // disabled. + @VisibleForTesting + public static final int TYPE_NONE = -1; private static final int CALLBACK_LISTEN_ALL = 1; private static final int CALLBACK_DEFAULT_INTERNET = 2; private static final int CALLBACK_MOBILE_REQUEST = 3; + private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray(); + static { + sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI); + sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH); + sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET); + } + private final Context mContext; private final SharedLog mLog; private final StateMachine mTarget; @@ -130,15 +149,15 @@ public class UpstreamNetworkMonitor { */ public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest, EntitlementManager entitle) { - // This is not really a "request", just a way of tracking the system default network. - // It's guaranteed not to actually bring up any networks because it's the same request - // as the ConnectivityService default request, and thus shares fate with it. We can't - // use registerDefaultNetworkCallback because it will not track the system default - // network if there is a VPN that applies to our UID. + + // defaultNetworkRequest is not really a "request", just a way of tracking the system + // default network. It's guaranteed not to actually bring up any networks because it's + // the should be the same request as the ConnectivityService default request, and thus + // shares fate with it. We can't use registerDefaultNetworkCallback because it will not + // track the system default network if there is a VPN that applies to our UID. if (mDefaultNetworkCallback == null) { - final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest); mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET); - cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler); + cm().requestNetwork(defaultNetworkRequest, mDefaultNetworkCallback, mHandler); } if (mEntitlementMgr == null) { mEntitlementMgr = entitle; @@ -198,19 +217,28 @@ public class UpstreamNetworkMonitor { mLog.e("registerMobileNetworkRequest() already registered"); return; } - // The following use of the legacy type system cannot be removed until - // after upstream selection no longer finds networks by legacy type. - // See also http://b/34364553 . - final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI; - final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder() - .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType)) - .build(); + final NetworkRequest mobileUpstreamRequest; + if (mDunRequired) { + mobileUpstreamRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_DUN) + .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) + .addTransportType(TRANSPORT_CELLULAR).build(); + } else { + mobileUpstreamRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_INTERNET) + .addTransportType(TRANSPORT_CELLULAR).build(); + } // The existing default network and DUN callbacks will be notified. // Therefore, to avoid duplicate notifications, we only register a no-op. mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST); + // The following use of the legacy type system cannot be removed until + // upstream selection no longer finds networks by legacy type. + // See also http://b/34364553 . + final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI; + // TODO: Change the timeout from 0 (no onUnavailable callback) to some // moderate callback timeout. This might be useful for updating some UI. // Additionally, we log a message to aid in any subsequent debugging. @@ -239,7 +267,7 @@ public class UpstreamNetworkMonitor { final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType( mNetworkMap.values(), preferredTypes, isCellularUpstreamPermitted()); - mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type)); + mLog.log("preferred upstream type: " + typeStatePair.type); switch (typeStatePair.type) { case TYPE_MOBILE_DUN: @@ -328,13 +356,6 @@ public class UpstreamNetworkMonitor { network, newNc)); } - // Log changes in upstream network signal strength, if available. - if (network.equals(mTetheringUpstreamNetwork) && newNc.hasSignalStrength()) { - final int newSignal = newNc.getSignalStrength(); - final String prevSignal = getSignalStrength(prev.networkCapabilities); - mLog.logf("upstream network signal strength: %s -> %s", prevSignal, newSignal); - } - mNetworkMap.put(network, new UpstreamNetworkState( prev.linkProperties, newNc, network)); // TODO: If sufficient information is available to select a more @@ -363,16 +384,6 @@ public class UpstreamNetworkMonitor { notifyTarget(EVENT_ON_LINKPROPERTIES, network); } - private void handleSuspended(Network network) { - if (!network.equals(mTetheringUpstreamNetwork)) return; - mLog.log("SUSPENDED current upstream: " + network); - } - - private void handleResumed(Network network) { - if (!network.equals(mTetheringUpstreamNetwork)) return; - mLog.log("RESUMED current upstream: " + network); - } - private void handleLost(Network network) { // There are few TODOs within ConnectivityService's rematching code // pertaining to spurious onLost() notifications. @@ -462,20 +473,6 @@ public class UpstreamNetworkMonitor { } @Override - public void onNetworkSuspended(Network network) { - if (mCallbackType == CALLBACK_LISTEN_ALL) { - handleSuspended(network); - } - } - - @Override - public void onNetworkResumed(Network network) { - if (mCallbackType == CALLBACK_LISTEN_ALL) { - handleResumed(network); - } - } - - @Override public void onLost(Network network) { if (mCallbackType == CALLBACK_DEFAULT_INTERNET) { mDefaultInternetNetwork = null; @@ -519,18 +516,15 @@ public class UpstreamNetworkMonitor { for (int type : preferredTypes) { NetworkCapabilities nc; try { - nc = ConnectivityManager.networkCapabilitiesForType(type); + nc = networkCapabilitiesForType(type); } catch (IllegalArgumentException iae) { - Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " - + ConnectivityManager.getNetworkTypeName(type)); + Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " + type); continue; } if (!isCellularUpstreamPermitted && isCellular(nc)) { continue; } - nc.setSingleUid(Process.myUid()); - for (UpstreamNetworkState value : netStates) { if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) { continue; @@ -557,11 +551,6 @@ public class UpstreamNetworkMonitor { return prefixSet; } - private static String getSignalStrength(NetworkCapabilities nc) { - if (nc == null || !nc.hasSignalStrength()) return "unknown"; - return Integer.toString(nc.getSignalStrength()); - } - private static boolean isCellular(UpstreamNetworkState ns) { return (ns != null) && isCellular(ns.networkCapabilities); } @@ -589,4 +578,28 @@ public class UpstreamNetworkMonitor { return null; } + + /** + * Given a legacy type (TYPE_WIFI, ...) returns the corresponding NetworkCapabilities instance. + * This function is used for deprecated legacy type and be disabled by default. + */ + @VisibleForTesting + public static NetworkCapabilities networkCapabilitiesForType(int type) { + final NetworkCapabilities nc = new NetworkCapabilities(); + + // Map from type to transports. + final int notFound = -1; + final int transport = sLegacyTypeToTransport.get(type, notFound); + Preconditions.checkArgument(transport != notFound, "unknown legacy type: " + type); + nc.addTransportType(transport); + + if (type == TYPE_MOBILE_DUN) { + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); + // DUN is restricted network, see NetworkCapabilities#FORCE_RESTRICTED_CAPABILITIES. + nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } else { + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + return nc; + } } diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index 81a0548cd718..53782fed1c50 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -20,7 +20,11 @@ android_test { srcs: [ "src/**/*.java", ], - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "mts", + ], + compile_multilib: "both", static_libs: [ "androidx.test.rules", "frameworks-base-testutils", diff --git a/packages/Tethering/tests/unit/jarjar-rules.txt b/packages/Tethering/tests/unit/jarjar-rules.txt index 64fdebd92726..921fbed373b0 100644 --- a/packages/Tethering/tests/unit/jarjar-rules.txt +++ b/packages/Tethering/tests/unit/jarjar-rules.txt @@ -7,5 +7,6 @@ rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering. rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1 rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 +rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 diff --git a/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java index e01ac7f08c2f..e8add9830b5f 100644 --- a/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java +++ b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java @@ -18,8 +18,6 @@ package android.net.dhcp; import static android.net.InetAddresses.parseNumericAddress; -import static com.google.android.collect.Sets.newHashSet; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -34,6 +32,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.Inet4Address; +import java.util.Arrays; +import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -47,9 +47,10 @@ public class DhcpServingParamsParcelExtTest { private static final int TEST_LEASE_TIME_SECS = 120; private static final int TEST_MTU = 1000; private static final Set<Inet4Address> TEST_ADDRESS_SET = - newHashSet(inet4Addr("192.168.1.123"), inet4Addr("192.168.1.124")); + new HashSet<Inet4Address>(Arrays.asList( + new Inet4Address[] {inet4Addr("192.168.1.123"), inet4Addr("192.168.1.124")})); private static final Set<Integer> TEST_ADDRESS_SET_PARCELED = - newHashSet(0xc0a8017b, 0xc0a8017c); + new HashSet<Integer>(Arrays.asList(new Integer[] {0xc0a8017b, 0xc0a8017c})); private DhcpServingParamsParcelExt mParcel; 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 4358cd6966f1..f29ad780b92c 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -16,13 +16,14 @@ package android.net.ip; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHERING_WIFI_P2P; -import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; +import static android.net.INetd.IF_STATE_UP; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.ip.IpServer.STATE_AVAILABLE; import static android.net.ip.IpServer.STATE_LOCAL_ONLY; @@ -51,8 +52,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.net.INetd; -import android.net.INetworkStatsService; -import android.net.InterfaceConfiguration; +import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; @@ -64,7 +64,6 @@ import android.net.dhcp.IDhcpServerCallbacks; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.SharedLog; -import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.test.TestLooper; import android.text.TextUtils; @@ -89,6 +88,8 @@ public class IpServerTest { private static final String IFACE_NAME = "testnet1"; private static final String UPSTREAM_IFACE = "upstream0"; private static final String UPSTREAM_IFACE2 = "upstream1"; + private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1"; + private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; private static final int DHCP_LEASE_TIME_SECS = 3600; private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams( @@ -96,11 +97,8 @@ public class IpServerTest { private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000; - @Mock private INetworkManagementService mNMService; @Mock private INetd mNetd; - @Mock private INetworkStatsService mStatsService; @Mock private IpServer.Callback mCallback; - @Mock private InterfaceConfiguration mInterfaceConfiguration; @Mock private SharedLog mSharedLog; @Mock private IDhcpServer mDhcpServer; @Mock private RouterAdvertisementDaemon mRaDaemon; @@ -112,6 +110,7 @@ public class IpServerTest { private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor = ArgumentCaptor.forClass(LinkProperties.class); private IpServer mIpServer; + private InterfaceConfigurationParcel mInterfaceConfiguration; private void initStateMachine(int interfaceType) throws Exception { initStateMachine(interfaceType, false /* usingLegacyDhcp */); @@ -131,17 +130,20 @@ public class IpServerTest { }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any()); when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon); when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS); - when(mDependencies.getNetdService()).thenReturn(mNetd); - + mInterfaceConfiguration = new InterfaceConfigurationParcel(); + mInterfaceConfiguration.flags = new String[0]; + if (interfaceType == TETHERING_BLUETOOTH) { + mInterfaceConfiguration.ipv4Addr = BLUETOOTH_IFACE_ADDR; + mInterfaceConfiguration.prefixLength = BLUETOOTH_DHCP_PREFIX_LENGTH; + } mIpServer = new IpServer( - IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, - mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies); + IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, + mCallback, usingLegacyDhcp, mDependencies); mIpServer.start(); // Starting the state machine always puts us in a consistent state and notifies // the rest of the world that we've changed from an unknown to available state. mLooper.dispatchAll(); - reset(mNMService, mStatsService, mCallback); - when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); + reset(mNetd, mCallback); when(mRaDaemon.start()).thenReturn(true); } @@ -158,8 +160,7 @@ public class IpServerTest { if (upstreamIface != null) { dispatchTetherConnectionChanged(upstreamIface); } - reset(mNMService, mStatsService, mCallback); - when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); + reset(mNetd, mCallback); } @Before public void setUp() throws Exception { @@ -169,15 +170,14 @@ public class IpServerTest { @Test public void startsOutAvailable() { - mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), - TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback, - false /* usingLegacyDhcp */, mDependencies); + mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, + mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies); mIpServer.start(); mLooper.dispatchAll(); verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mCallback, mNMService, mStatsService); + verifyNoMoreInteractions(mCallback, mNetd); } @Test @@ -196,7 +196,7 @@ public class IpServerTest { // None of these commands should trigger us to request action from // the rest of the system. dispatchCommand(command); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } } @@ -208,7 +208,7 @@ public class IpServerTest { verify(mCallback).updateInterfaceState( mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -216,13 +216,17 @@ public class IpServerTest { initStateMachine(TETHERING_BLUETOOTH); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); - InOrder inOrder = inOrder(mCallback, mNMService); - inOrder.verify(mNMService).tetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mCallback, mNetd); + inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); + 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_TETHERED, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -230,14 +234,16 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, null); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); - InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback); - inOrder.verify(mNMService).untetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mNetd, mCallback); + 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(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -245,16 +251,19 @@ public class IpServerTest { initStateMachine(TETHERING_USB); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); - InOrder inOrder = inOrder(mCallback, mNMService); - inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME); - inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); - inOrder.verify(mNMService).tetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mCallback, mNetd); + inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> + IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); + inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); + inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); + inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), + any(), any()); inOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), mLinkPropertiesCaptor.capture()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -262,16 +271,19 @@ public class IpServerTest { initStateMachine(TETHERING_WIFI_P2P); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); - InOrder inOrder = inOrder(mCallback, mNMService); - inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME); - inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); - inOrder.verify(mNMService).tetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mCallback, mNetd); + inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> + IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); + inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); + inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); + 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), mLinkPropertiesCaptor.capture()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -281,10 +293,10 @@ public class IpServerTest { // Telling the state machine about its upstream interface triggers // a little more configuration. dispatchTetherConnectionChanged(UPSTREAM_IFACE); - InOrder inOrder = inOrder(mNMService); - inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + InOrder inOrder = inOrder(mNetd); + inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -292,49 +304,44 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNMService, mStatsService); - inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + InOrder inOrder = inOrder(mNetd); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); + verifyNoMoreInteractions(mNetd, mCallback); } @Test public void handlesChangingUpstreamNatFailure() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); - doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); + doThrow(RemoteException.class).when(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNMService, mStatsService); - inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2); + InOrder inOrder = inOrder(mNetd); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2); } @Test public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); - doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding( + doThrow(RemoteException.class).when(mNetd).ipfwdAddInterfaceForward( IFACE_NAME, UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNMService, mStatsService); - inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2); + InOrder inOrder = inOrder(mNetd); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2); } @Test @@ -342,17 +349,18 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); - InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback); - inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).untetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mNetd, mCallback); + 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(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -361,13 +369,14 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_USB, null); if (shouldThrow) { - doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME); + doThrow(RemoteException.class).when(mNetd).tetherInterfaceRemove(IFACE_NAME); } dispatchCommand(IpServer.CMD_INTERFACE_DOWN); - InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback); - usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); - usbTeardownOrder.verify(mNMService).setInterfaceConfig( - IFACE_NAME, mInterfaceConfiguration); + InOrder usbTeardownOrder = inOrder(mNetd, mCallback); + // Currently IpServer interfaceSetCfg twice to stop IPv4. One just set interface down + // Another one is set IPv4 to 0.0.0.0/0 as clearng ipv4 address. + usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg( + argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); usbTeardownOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); usbTeardownOrder.verify(mCallback).updateLinkProperties( @@ -380,12 +389,15 @@ public class IpServerTest { public void usbShouldBeTornDownOnTetherError() throws Exception { initStateMachine(TETHERING_USB); - doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME); + doThrow(RemoteException.class).when(mNetd).tetherInterfaceAdd(IFACE_NAME); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); - InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback); - usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); - usbTeardownOrder.verify(mNMService).setInterfaceConfig( - IFACE_NAME, mInterfaceConfiguration); + InOrder usbTeardownOrder = inOrder(mNetd, mCallback); + usbTeardownOrder.verify(mNetd).interfaceSetCfg( + argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); + usbTeardownOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); + + usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg( + argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); usbTeardownOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR); usbTeardownOrder.verify(mCallback).updateLinkProperties( @@ -397,11 +409,13 @@ public class IpServerTest { public void shouldTearDownUsbOnUpstreamError() throws Exception { initTetheredStateMachine(TETHERING_USB, null); - doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString()); + doThrow(RemoteException.class).when(mNetd).tetherAddForward(anyString(), anyString()); dispatchTetherConnectionChanged(UPSTREAM_IFACE); - InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback); - usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); - usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); + InOrder usbTeardownOrder = inOrder(mNetd, mCallback); + usbTeardownOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE); + + usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg( + argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); usbTeardownOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR); usbTeardownOrder.verify(mCallback).updateLinkProperties( @@ -413,11 +427,11 @@ public class IpServerTest { public void ignoresDuplicateUpstreamNotifications() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); for (int i = 0; i < 5; i++) { dispatchTetherConnectionChanged(UPSTREAM_IFACE); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } } @@ -510,8 +524,10 @@ public class IpServerTest { } assertNotNull("missing IPv4 address", addr4); + final IpPrefix destination = new IpPrefix(addr4.getAddress(), addr4.getPrefixLength()); // Assert the presence of the associated directly connected route. - final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName()); + final RouteInfo directlyConnected = new RouteInfo(destination, null, lp.getInterfaceName(), + RouteInfo.RTN_UNICAST); assertTrue("missing directly connected route: '" + directlyConnected.toString() + "'", lp.getRoutes().contains(directlyConnected)); } @@ -523,4 +539,22 @@ public class IpServerTest { // never see an empty interface name in any LinkProperties update. assertFalse(TextUtils.isEmpty(lp.getInterfaceName())); } + + private boolean assertContainsFlag(String[] flags, String match) { + for (String flag : flags) { + if (flag.equals(match)) return true; + } + fail("Missing flag: " + match); + return false; + } + + private boolean assertNotContainsFlag(String[] flags, String match) { + for (String flag : flags) { + if (flag.equals(match)) { + fail("Unexpected flag: " + match); + return false; + } + } + return true; + } } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java index 99cf9e90d912..4f0746199786 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -16,12 +16,13 @@ package com.android.server.connectivity.tethering; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -39,7 +40,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.util.SharedLog; @@ -49,18 +49,16 @@ import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.SystemProperties; import android.os.test.TestLooper; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.telephony.CarrierConfigManager; -import android.test.mock.MockContentResolver; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.R; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.internal.util.test.FakeSettingsProvider; +import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; @@ -94,7 +92,6 @@ public final class EntitlementManagerTest { private final PersistableBundle mCarrierConfig = new PersistableBundle(); private final TestLooper mLooper = new TestLooper(); private Context mMockContext; - private MockContentResolver mContentResolver; private TestStateMachine mSM; private WrappedEntitlementManager mEnMgr; @@ -110,11 +107,6 @@ public final class EntitlementManagerTest { public Resources getResources() { return mResources; } - - @Override - public ContentResolver getContentResolver() { - return mContentResolver; - } } public class WrappedEntitlementManager extends EntitlementManager { @@ -151,28 +143,33 @@ public final class EntitlementManagerTest { MockitoAnnotations.initMocks(this); mMockingSession = mockitoSession() .initMocks(this) - .spyStatic(SystemProperties.class) + .mockStatic(SystemProperties.class) + .mockStatic(DeviceConfig.class) .strictness(Strictness.WARN) .startMocking(); // Don't disable tethering provisioning unless requested. doReturn(false).when( () -> SystemProperties.getBoolean( eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean())); + doReturn(false).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); when(mResources.getStringArray(R.array.config_tether_dhcp_range)) - .thenReturn(new String[0]); + .thenReturn(new String[0]); when(mResources.getStringArray(R.array.config_tether_usb_regexs)) - .thenReturn(new String[0]); + .thenReturn(new String[0]); when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) - .thenReturn(new String[0]); + .thenReturn(new String[0]); when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) - .thenReturn(new String[0]); + .thenReturn(new String[0]); when(mResources.getIntArray(R.array.config_tether_upstream_types)) - .thenReturn(new int[0]); + .thenReturn(new int[0]); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); + when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn(""); when(mLog.forSubComponent(anyString())).thenReturn(mLog); - mContentResolver = new MockContentResolver(); - mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mMockContext = new MockContext(mContext); mSM = new TestStateMachine(); mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE); diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java index 8574f5401496..7e62e5aca993 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java @@ -16,20 +16,26 @@ package com.android.server.connectivity.tethering; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.STATS_PER_IFACE; -import static android.net.NetworkStats.STATS_PER_UID; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.UID_TETHERING; +import static android.net.NetworkStats.UID_TETHERING; +import static android.net.RouteInfo.RTN_UNICAST; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; +import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_IFACE; +import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_UID; import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; +import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; @@ -38,11 +44,14 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.annotation.NonNull; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.net.ITetheringStatsProvider; @@ -50,10 +59,12 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkStats; +import android.net.NetworkStats.Entry; import android.net.RouteInfo; +import android.net.netstats.provider.AbstractNetworkStatsProvider; +import android.net.netstats.provider.NetworkStatsProviderCallback; import android.net.util.SharedLog; import android.os.Handler; -import android.os.INetworkManagementService; import android.os.Looper; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -96,11 +107,13 @@ public class OffloadControllerTest { @Mock private OffloadHardwareInterface mHardware; @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; - @Mock private INetworkManagementService mNMService; + @Mock private NetworkStatsManager mStatsManager; + @Mock private NetworkStatsProviderCallback mTetherStatsProviderCb; private final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class); - private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor = - ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class); + private final ArgumentCaptor<OffloadController.OffloadTetheringStatsProvider> + mTetherStatsProviderCaptor = + ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor = ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class); private MockContentResolver mContentResolver; @@ -113,6 +126,8 @@ public class OffloadControllerTest { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolver); FakeSettingsProvider.clearSettingsProvider(); + when(mStatsManager.registerNetworkStatsProvider(anyString(), any())) + .thenReturn(mTetherStatsProviderCb); } @After public void tearDown() throws Exception { @@ -138,9 +153,9 @@ public class OffloadControllerTest { private OffloadController makeOffloadController() throws Exception { OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()), - mHardware, mContentResolver, mNMService, new SharedLog("test")); - verify(mNMService).registerTetheringStatsProvider( - mTetherStatsProviderCaptor.capture(), anyString()); + mHardware, mContentResolver, mStatsManager, new SharedLog("test")); + verify(mStatsManager).registerNetworkStatsProvider(anyString(), + mTetherStatsProviderCaptor.capture()); return offload; } @@ -269,7 +284,7 @@ public class OffloadControllerTest { final String ipv4Addr = "192.0.2.5"; final String linkAddr = ipv4Addr + "/24"; lp.addLinkAddress(new LinkAddress(linkAddr)); - lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"))); + lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, null, RTN_UNICAST)); offload.setUpstreamLinkProperties(lp); // IPv4 prefixes and addresses on the upstream are simply left as whole // prefixes (already passed in from UpstreamNetworkMonitor code). If a @@ -285,7 +300,7 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); final String ipv4Gateway = "192.0.2.1"; - lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway))); + lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv4Gateway), null, RTN_UNICAST)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); @@ -296,7 +311,7 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); final String ipv6Gw1 = "fe80::cafe"; - lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1))); + lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv6Gw1), null, RTN_UNICAST)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); @@ -310,7 +325,7 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); final String ipv6Gw2 = "fe80::d00d"; - lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2))); + lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv6Gw2), null, RTN_UNICAST)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); @@ -327,8 +342,10 @@ public class OffloadControllerTest { final LinkProperties stacked = new LinkProperties(); stacked.setInterfaceName("stacked"); stacked.addLinkAddress(new LinkAddress("192.0.2.129/25")); - stacked.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254"))); - stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00"))); + stacked.addRoute(new RouteInfo(null, InetAddress.getByName("192.0.2.254"), null, + RTN_UNICAST)); + stacked.addRoute(new RouteInfo(null, InetAddress.getByName("fe80::bad:f00"), null, + RTN_UNICAST)); assertTrue(lp.addStackedLink(stacked)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). @@ -348,7 +365,7 @@ public class OffloadControllerTest { // removed from "local prefixes" and /128s added for the upstream IPv6 // addresses. This is not yet implemented, and for now we simply // expect to see these /128s. - lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64"))); + lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64"), null, null, RTN_UNICAST)); // "2001:db8::/64" plus "assigned" ASCII in hex lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64")); // "2001:db8::/64" plus "random" ASCII in hex @@ -381,12 +398,11 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); } - private void assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry) { - assertEquals(iface, entry.iface); - assertEquals(stats.rxBytes, entry.rxBytes); - assertEquals(stats.txBytes, entry.txBytes); - assertEquals(SET_DEFAULT, entry.set); - assertEquals(TAG_NONE, entry.tag); + private static @NonNull Entry buildTestEntry(@NonNull OffloadController.StatsType how, + @NonNull String iface, long rxBytes, long txBytes) { + return new Entry(iface, how == STATS_PER_IFACE ? UID_ALL : UID_TETHERING, SET_DEFAULT, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, 0L, + txBytes, 0L, 0L); } @Test @@ -397,19 +413,16 @@ public class OffloadControllerTest { final OffloadController offload = makeOffloadController(); offload.start(); + final OffloadController.OffloadTetheringStatsProvider provider = + mTetherStatsProviderCaptor.getValue(); + final String ethernetIface = "eth1"; final String mobileIface = "rmnet_data0"; - ForwardedStats ethernetStats = new ForwardedStats(); - ethernetStats.rxBytes = 12345; - ethernetStats.txBytes = 54321; - - ForwardedStats mobileStats = new ForwardedStats(); - mobileStats.rxBytes = 999; - mobileStats.txBytes = 99999; - - when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats); - when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(mobileStats); + when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( + new ForwardedStats(12345, 54321)); + when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn( + new ForwardedStats(999, 99999)); InOrder inOrder = inOrder(mHardware); @@ -429,10 +442,35 @@ public class OffloadControllerTest { // Expect that we fetch stats from the previous upstream. inOrder.verify(mHardware, times(1)).getForwardedStats(eq(mobileIface)); - ethernetStats = new ForwardedStats(); - ethernetStats.rxBytes = 100000; - ethernetStats.txBytes = 100000; - when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats); + // Verify that the fetched stats are stored. + final NetworkStats ifaceStats = provider.getTetherStats(STATS_PER_IFACE); + final NetworkStats uidStats = provider.getTetherStats(STATS_PER_UID); + final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) + .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321)); + + final NetworkStats expectedUidStats = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) + .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321)); + + assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStats)); + assertTrue(orderInsensitiveEquals(expectedUidStats, uidStats)); + + final ArgumentCaptor<NetworkStats> ifaceStatsCaptor = ArgumentCaptor.forClass( + NetworkStats.class); + final ArgumentCaptor<NetworkStats> uidStatsCaptor = ArgumentCaptor.forClass( + NetworkStats.class); + + // Force pushing stats update to verify the stats reported. + provider.pushTetherStats(); + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), + ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); + assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStatsCaptor.getValue())); + assertTrue(orderInsensitiveEquals(expectedUidStats, uidStatsCaptor.getValue())); + + + when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( + new ForwardedStats(100000, 100000)); offload.setUpstreamLinkProperties(null); // Expect that we first clear the HAL's upstream parameters. inOrder.verify(mHardware, times(1)).setUpstreamParameters( @@ -440,37 +478,38 @@ public class OffloadControllerTest { // Expect that we fetch stats from the previous upstream. inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface)); - ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue(); - NetworkStats stats = provider.getTetherStats(STATS_PER_IFACE); - NetworkStats perUidStats = provider.getTetherStats(STATS_PER_UID); - waitForIdle(); // There is no current upstream, so no stats are fetched. inOrder.verify(mHardware, never()).getForwardedStats(any()); inOrder.verifyNoMoreInteractions(); - assertEquals(2, stats.size()); - assertEquals(2, perUidStats.size()); - - NetworkStats.Entry entry = null; - for (int i = 0; i < stats.size(); i++) { - assertEquals(UID_ALL, stats.getValues(i, entry).uid); - assertEquals(UID_TETHERING, perUidStats.getValues(i, entry).uid); - } - - int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1; - int mobilePosition = 1 - ethernetPosition; - - entry = stats.getValues(mobilePosition, entry); - assertNetworkStats(mobileIface, mobileStats, entry); - entry = perUidStats.getValues(mobilePosition, entry); - assertNetworkStats(mobileIface, mobileStats, entry); - - ethernetStats.rxBytes = 12345 + 100000; - ethernetStats.txBytes = 54321 + 100000; - entry = stats.getValues(ethernetPosition, entry); - assertNetworkStats(ethernetIface, ethernetStats, entry); - entry = perUidStats.getValues(ethernetPosition, entry); - assertNetworkStats(ethernetIface, ethernetStats, entry); + // Verify that the stored stats is accumulated. + final NetworkStats ifaceStatsAccu = provider.getTetherStats(STATS_PER_IFACE); + final NetworkStats uidStatsAccu = provider.getTetherStats(STATS_PER_UID); + final NetworkStats expectedIfaceStatsAccu = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) + .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321)); + + final NetworkStats expectedUidStatsAccu = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) + .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321)); + + assertTrue(orderInsensitiveEquals(expectedIfaceStatsAccu, ifaceStatsAccu)); + assertTrue(orderInsensitiveEquals(expectedUidStatsAccu, uidStatsAccu)); + + // Verify that only diff of stats is reported. + reset(mTetherStatsProviderCb); + provider.pushTetherStats(); + final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) + .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000)); + + final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) + .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), + ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); + assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue())); + assertTrue(orderInsensitiveEquals(expectedUidStatsDiff, uidStatsCaptor.getValue())); } @Test @@ -490,19 +529,19 @@ public class OffloadControllerTest { lp.setInterfaceName(ethernetIface); offload.setUpstreamLinkProperties(lp); - ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue(); + AbstractNetworkStatsProvider provider = mTetherStatsProviderCaptor.getValue(); final InOrder inOrder = inOrder(mHardware); when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); // Applying an interface quota to the current upstream immediately sends it to the hardware. - provider.setInterfaceQuota(ethernetIface, ethernetLimit); + provider.setLimit(ethernetIface, ethernetLimit); waitForIdle(); inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit); inOrder.verifyNoMoreInteractions(); // Applying an interface quota to another upstream does not take any immediate action. - provider.setInterfaceQuota(mobileIface, mobileLimit); + provider.setLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); @@ -515,7 +554,7 @@ public class OffloadControllerTest { // Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set // to Long.MAX_VALUE. - provider.setInterfaceQuota(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); + provider.setLimit(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); waitForIdle(); inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE); @@ -523,7 +562,7 @@ public class OffloadControllerTest { when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false); lp.setInterfaceName(ethernetIface); offload.setUpstreamLinkProperties(lp); - provider.setInterfaceQuota(mobileIface, mobileLimit); + provider.setLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); @@ -532,7 +571,7 @@ public class OffloadControllerTest { when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false); lp.setInterfaceName(mobileIface); offload.setUpstreamLinkProperties(lp); - provider.setInterfaceQuota(mobileIface, mobileLimit); + provider.setLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware).getForwardedStats(ethernetIface); inOrder.verify(mHardware).stopOffloadControl(); @@ -548,7 +587,7 @@ public class OffloadControllerTest { OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); callback.onStoppedLimitReached(); - verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); } @Test @@ -574,13 +613,15 @@ public class OffloadControllerTest { final LinkProperties usbLinkProperties = new LinkProperties(); usbLinkProperties.setInterfaceName(RNDIS0); usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX))); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, USB_PREFIX); inOrder.verifyNoMoreInteractions(); // [2] Routes for IPv6 link-local prefixes should never be added. - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL))); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString()); inOrder.verifyNoMoreInteractions(); @@ -588,7 +629,8 @@ public class OffloadControllerTest { // [3] Add an IPv6 prefix for good measure. Only new offload-able // prefixes should be passed to the HAL. usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64")); - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX))); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX); inOrder.verifyNoMoreInteractions(); @@ -601,8 +643,10 @@ public class OffloadControllerTest { // [5] Differences in local routes are converted into addDownstream() // and removeDownstream() invocations accordingly. - usbLinkProperties.removeRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, RNDIS0)); - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX))); + usbLinkProperties.removeRoute( + new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, RNDIS0, RTN_UNICAST)); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX); inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX); @@ -646,9 +690,10 @@ public class OffloadControllerTest { // Verify forwarded stats behaviour. verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); + // TODO: verify the exact stats reported. + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verifyNoMoreInteractions(mTetherStatsProviderCb); verifyNoMoreInteractions(mHardware); - verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); - verifyNoMoreInteractions(mNMService); } @Test @@ -680,19 +725,23 @@ public class OffloadControllerTest { final LinkProperties usbLinkProperties = new LinkProperties(); usbLinkProperties.setInterfaceName(RNDIS0); usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX))); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); final LinkProperties wifiLinkProperties = new LinkProperties(); wifiLinkProperties.setInterfaceName(WLAN0); wifiLinkProperties.addLinkAddress(new LinkAddress("192.168.43.1/24")); - wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(WIFI_PREFIX))); - wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL))); + wifiLinkProperties.addRoute( + new RouteInfo(new IpPrefix(WIFI_PREFIX), null, null, RTN_UNICAST)); + wifiLinkProperties.addRoute( + new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST)); // Use a benchmark prefix (RFC 5180 + erratum), since the documentation // prefix is included in the excluded prefix list. wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::1/64")); wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::2/64")); - wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix("2001:2::/64"))); + wifiLinkProperties.addRoute( + new RouteInfo(new IpPrefix("2001:2::/64"), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(wifiLinkProperties); offload.removeDownstreamInterface(RNDIS0); @@ -707,8 +756,8 @@ public class OffloadControllerTest { // Verify forwarded stats behaviour. verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); - verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); - verifyNoMoreInteractions(mNMService); + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verifyNoMoreInteractions(mTetherStatsProviderCb); // TODO: verify local prefixes and downstreams are also pushed to the HAL. verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java index 30bff3560955..3635964dd6a6 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -21,41 +21,38 @@ import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.internal.R.array.config_mobile_hotspot_provision_app; -import static com.android.internal.R.array.config_tether_bluetooth_regexs; -import static com.android.internal.R.array.config_tether_dhcp_range; -import static com.android.internal.R.array.config_tether_upstream_types; -import static com.android.internal.R.array.config_tether_usb_regexs; -import static com.android.internal.R.array.config_tether_wifi_regexs; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.when; -import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.util.SharedLog; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.telephony.TelephonyManager; -import android.test.mock.MockContentResolver; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.internal.util.test.FakeSettingsProvider; +import com.android.networkstack.tethering.R; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import java.util.Arrays; import java.util.Iterator; @@ -70,9 +67,10 @@ public class TetheringConfigurationTest { @Mock private TelephonyManager mTelephonyManager; @Mock private Resources mResources; @Mock private Resources mResourcesForSubId; - private MockContentResolver mContentResolver; private Context mMockContext; private boolean mHasTelephonyManager; + private boolean mEnableLegacyDhcpServer; + private MockitoSession mMockingSession; private class MockTetheringConfiguration extends TetheringConfiguration { MockTetheringConfiguration(Context ctx, SharedLog log, int id) { @@ -102,32 +100,44 @@ public class TetheringConfigurationTest { } return super.getSystemService(name); } - - @Override - public ContentResolver getContentResolver() { - return mContentResolver; - } } @Before public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(mResources.getStringArray(config_tether_dhcp_range)).thenReturn(new String[0]); - when(mResources.getStringArray(config_tether_usb_regexs)).thenReturn(new String[0]); - when(mResources.getStringArray(config_tether_wifi_regexs)) + // TODO: use a dependencies class instead of mock statics. + mMockingSession = mockitoSession() + .initMocks(this) + .mockStatic(DeviceConfig.class) + .strictness(Strictness.WARN) + .startMocking(); + doReturn(false).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + + when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn( + new String[0]); + when(mResources.getStringArray(R.array.config_tether_usb_regexs)).thenReturn(new String[0]); + when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) .thenReturn(new String[]{ "test_wlan\\d" }); - when(mResources.getStringArray(config_tether_bluetooth_regexs)).thenReturn(new String[0]); - when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); - when(mResources.getStringArray(config_mobile_hotspot_provision_app)) + when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)).thenReturn( + new String[0]); + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); + when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) .thenReturn(new String[0]); - mContentResolver = new MockContentResolver(); - mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); mHasTelephonyManager = true; mMockContext = new MockContext(mContext); + mEnableLegacyDhcpServer = false; + } + + @After + public void tearDown() throws Exception { + mMockingSession.finishMocking(); } private TetheringConfiguration getTetheringConfiguration(int... legacyTetherUpstreamTypes) { - when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( legacyTetherUpstreamTypes); return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); } @@ -145,7 +155,7 @@ public class TetheringConfigurationTest { @Test public void testDunFromTelephonyManagerMeansDun() { - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(true); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(true); final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( @@ -169,7 +179,7 @@ public class TetheringConfigurationTest { @Test public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( @@ -211,8 +221,8 @@ public class TetheringConfigurationTest { @Test public void testNoDefinedUpstreamTypesAddsEthernet() { - when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{}); - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[]{}); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -233,9 +243,9 @@ public class TetheringConfigurationTest { @Test public void testDefinedUpstreamTypesSansEthernetAddsEthernet() { - when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -251,9 +261,9 @@ public class TetheringConfigurationTest { @Test public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() { - when(mResources.getIntArray(config_tether_upstream_types)) + when(mResources.getIntArray(R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI}); - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -269,19 +279,38 @@ public class TetheringConfigurationTest { @Test public void testNewDhcpServerDisabled() { - Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); - - final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); - assertTrue(cfg.enableLegacyDhcpServer); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + true); + doReturn(false).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + + final TetheringConfiguration enableByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByRes.enableLegacyDhcpServer); + + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); + doReturn(true).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + + final TetheringConfiguration enableByDevConfig = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByDevConfig.enableLegacyDhcpServer); } @Test public void testNewDhcpServerEnabled() { - Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); + doReturn(false).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + + final TetheringConfiguration cfg = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); - final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertFalse(cfg.enableLegacyDhcpServer); } @@ -300,16 +329,17 @@ public class TetheringConfigurationTest { private void setUpResourceForSubId() { when(mResourcesForSubId.getStringArray( - config_tether_dhcp_range)).thenReturn(new String[0]); + R.array.config_tether_dhcp_range)).thenReturn(new String[0]); when(mResourcesForSubId.getStringArray( - config_tether_usb_regexs)).thenReturn(new String[0]); + R.array.config_tether_usb_regexs)).thenReturn(new String[0]); when(mResourcesForSubId.getStringArray( - config_tether_wifi_regexs)).thenReturn(new String[]{ "test_wlan\\d" }); + R.array.config_tether_wifi_regexs)).thenReturn(new String[]{ "test_wlan\\d" }); when(mResourcesForSubId.getStringArray( - config_tether_bluetooth_regexs)).thenReturn(new String[0]); - when(mResourcesForSubId.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); + R.array.config_tether_bluetooth_regexs)).thenReturn(new String[0]); + when(mResourcesForSubId.getIntArray(R.array.config_tether_upstream_types)).thenReturn( + new int[0]); when(mResourcesForSubId.getStringArray( - config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME); + R.array.config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME); } } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 0bc8c7944615..affd69154b70 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -19,15 +19,18 @@ package com.android.server.connectivity.tethering; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; -import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; -import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY; -import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER; -import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; -import static android.net.ConnectivityManager.TYPE_WIFI_P2P; +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; +import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; +import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER; +import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; @@ -35,7 +38,6 @@ import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; -import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertArrayEquals; @@ -49,10 +51,10 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; @@ -60,6 +62,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.app.usage.NetworkStatsManager; +import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -68,20 +72,18 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.res.Resources; import android.hardware.usb.UsbManager; +import android.net.ConnectivityManager; import android.net.INetd; -import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; import android.net.ITetheringEventCallback; -import android.net.InterfaceConfiguration; +import android.net.InetAddresses; +import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkInfo; import android.net.NetworkRequest; -import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.TetherStatesParcel; import android.net.TetheringConfigurationParcel; @@ -100,7 +102,6 @@ import android.net.wifi.p2p.WifiP2pInfo; import android.net.wifi.p2p.WifiP2pManager; import android.os.Bundle; import android.os.Handler; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.PersistableBundle; import android.os.RemoteException; @@ -121,6 +122,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; +import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; @@ -134,6 +136,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Vector; @RunWith(AndroidJUnit4.class) @@ -146,14 +149,13 @@ public class TetheringTest { private static final String TEST_USB_IFNAME = "test_rndis0"; private static final String TEST_WLAN_IFNAME = "test_wlan0"; private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0"; + private static final String TETHERING_NAME = "Tethering"; private static final int DHCPSERVER_START_TIMEOUT_MS = 1000; @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; - @Mock private INetworkManagementService mNMService; - @Mock private INetworkStatsService mStatsService; - @Mock private INetworkPolicyManager mPolicyManager; + @Mock private NetworkStatsManager mStatsManager; @Mock private OffloadHardwareInterface mOffloadHardwareInterface; @Mock private Resources mResources; @Mock private TelephonyManager mTelephonyManager; @@ -167,6 +169,7 @@ public class TetheringTest { @Mock private INetd mNetd; @Mock private UserManager mUserManager; @Mock private NetworkRequest mNetworkRequest; + @Mock private ConnectivityManager mCm; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -184,6 +187,7 @@ public class TetheringTest { private BroadcastReceiver mBroadcastReceiver; private Tethering mTethering; private PhoneStateListener mPhoneStateListener; + private InterfaceConfigurationParcel mInterfaceConfiguration; private class TestContext extends BroadcastInterceptingContext { TestContext(Context base) { @@ -216,6 +220,8 @@ public class TetheringTest { if (Context.USB_SERVICE.equals(name)) return mUsbManager; if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager; if (Context.USER_SERVICE.equals(name)) return mUserManager; + if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager; + if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm; return super.getSystemService(name); } @@ -224,6 +230,11 @@ public class TetheringTest { if (TelephonyManager.class.equals(serviceClass)) return Context.TELEPHONY_SERVICE; return super.getSystemServiceName(serviceClass); } + + @Override + public Context createContextAsUser(UserHandle user, int flags) { + return mContext; + } } public class MockIpServerDependencies extends IpServer.Dependencies { @@ -247,11 +258,6 @@ public class TetheringTest { } @Override - public INetd getNetdService() { - return mNetd; - } - - @Override public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb) { new Thread(() -> { @@ -270,6 +276,11 @@ public class TetheringTest { } @Override + protected boolean getDeviceConfigBoolean(final String name) { + return false; + } + + @Override protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { return mResources; } @@ -328,21 +339,6 @@ public class TetheringTest { } @Override - public INetworkManagementService getINetworkManagementService() { - return mNMService; - } - - @Override - public INetworkStatsService getINetworkStatsService() { - return mStatsService; - } - - @Override - public INetworkPolicyManager getINetworkPolicyManager() { - return mPolicyManager; - } - - @Override public INetd getINetd(Context context) { return mNetd; } @@ -356,6 +352,12 @@ public class TetheringTest { public Context getContext() { return mServiceContext; } + + @Override + public BluetoothAdapter getBluetoothAdapter() { + // TODO: add test for bluetooth tethering. + return null; + } } private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4, @@ -365,23 +367,26 @@ public class TetheringTest { if (withIPv4) { prop.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), - NetworkUtils.numericToInetAddress("10.0.0.1"), TEST_MOBILE_IFNAME)); + InetAddresses.parseNumericAddress("10.0.0.1"), + TEST_MOBILE_IFNAME, RTN_UNICAST)); } if (withIPv6) { - prop.addDnsServer(NetworkUtils.numericToInetAddress("2001:db8::2")); + prop.addDnsServer(InetAddresses.parseNumericAddress("2001:db8::2")); prop.addLinkAddress( - new LinkAddress(NetworkUtils.numericToInetAddress("2001:db8::"), + new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"), NetworkConstants.RFC7421_PREFIX_LENGTH)); prop.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), - NetworkUtils.numericToInetAddress("2001:db8::1"), TEST_MOBILE_IFNAME)); + InetAddresses.parseNumericAddress("2001:db8::1"), + TEST_MOBILE_IFNAME, RTN_UNICAST)); } if (with464xlat) { final LinkProperties stackedLink = new LinkProperties(); stackedLink.setInterfaceName(TEST_XLAT_MOBILE_IFNAME); stackedLink.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), - NetworkUtils.numericToInetAddress("192.0.0.1"), TEST_XLAT_MOBILE_IFNAME)); + InetAddresses.parseNumericAddress("192.0.0.1"), + TEST_XLAT_MOBILE_IFNAME, RTN_UNICAST)); prop.addStackedLink(stackedLink); } @@ -411,32 +416,33 @@ public class TetheringTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range)) + when(mResources.getStringArray(R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs)) + when(mResources.getStringArray(R.array.config_tether_usb_regexs)) .thenReturn(new String[] { "test_rndis\\d" }); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs)) + when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) .thenReturn(new String[]{ "test_wlan\\d" }); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs)) + when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" }); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs)) + when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) .thenReturn(new String[0]); - when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) - .thenReturn(new int[0]); - when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic)) - .thenReturn(false); - when(mNMService.listInterfaces()) + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); + when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); + when(mNetd.interfaceGetList()) .thenReturn(new String[] { TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME}); - when(mNMService.getInterfaceConfig(anyString())) - .thenReturn(new InterfaceConfiguration()); + when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn(""); + mInterfaceConfiguration = new InterfaceConfigurationParcel(); + mInterfaceConfiguration.flags = new String[0]; when(mRouterAdvertisementDaemon.start()) .thenReturn(true); mServiceContext = new TestContext(mContext); + when(mContext.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(null); mContentResolver = new MockContentResolver(mServiceContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); - Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); mIntents = new Vector<>(); mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -447,7 +453,7 @@ public class TetheringTest { mServiceContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_TETHER_STATE_CHANGED)); mTethering = makeTethering(); - verify(mNMService).registerTetheringStatsProvider(any(), anyString()); + verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any()); verify(mNetd).registerUnsolicitedEventListener(any()); final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor = ArgumentCaptor.forClass(PhoneStateListener.class); @@ -487,20 +493,21 @@ public class TetheringTest { private void sendWifiP2pConnectionChanged( boolean isGroupFormed, boolean isGroupOwner, String ifname) { + WifiP2pGroup group = null; WifiP2pInfo p2pInfo = new WifiP2pInfo(); p2pInfo.groupFormed = isGroupFormed; - p2pInfo.isGroupOwner = isGroupOwner; - - NetworkInfo networkInfo = new NetworkInfo(TYPE_WIFI_P2P, 0, null, null); + if (isGroupFormed) { + p2pInfo.isGroupOwner = isGroupOwner; + group = mock(WifiP2pGroup.class); + when(group.isGroupOwner()).thenReturn(isGroupOwner); + when(group.getInterface()).thenReturn(ifname); + } - WifiP2pGroup group = new WifiP2pGroup(); - group.setIsGroupOwner(isGroupOwner); - group.setInterface(ifname); + final Intent intent = mock(Intent.class); + when(intent.getAction()).thenReturn(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); + when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO)).thenReturn(p2pInfo); + when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP)).thenReturn(group); - final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo); - intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, networkInfo); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group); mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL, P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST); } @@ -519,10 +526,11 @@ public class TetheringTest { } private void verifyInterfaceServingModeStarted(String ifname) throws Exception { - verify(mNMService, times(1)).getInterfaceConfig(ifname); - verify(mNMService, times(1)) - .setInterfaceConfig(eq(ifname), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).tetherInterface(ifname); + verify(mNetd, times(1)).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, times(1)).tetherInterfaceAdd(ifname); + verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, ifname); + verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(ifname), + anyString(), anyString()); } private void verifyTetheringBroadcast(String ifname, String whichExtra) { @@ -554,7 +562,7 @@ public class TetheringTest { verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); } - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); verifyNoMoreInteractions(mWifiManager); } @@ -577,14 +585,14 @@ public class TetheringTest { prepareUsbTethering(upstreamState); // This should produce no activity of any kind. - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Pretend we then receive USB configured broadcast. sendUsbBroadcast(true, true, true); mLooper.dispatchAll(); // Now we should see the start of tethering mechanics (in this case: // tetherMatchingInterfaces() which starts by fetching all interfaces). - verify(mNMService, times(1)).listInterfaces(); + verify(mNetd, times(1)).interfaceGetList(); // UpstreamNetworkMonitor should receive selected upstream verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any()); @@ -614,9 +622,9 @@ public class TetheringTest { verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); - verify(mNMService, times(1)).setIpForwardingEnabled(true); - verify(mNMService, times(1)).startTethering(any(String[].class)); - verifyNoMoreInteractions(mNMService); + verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, times(1)).tetherStartWithConfiguration(any()); + verifyNoMoreInteractions(mNetd); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verify(mWifiManager).updateInterfaceIpState( @@ -634,16 +642,16 @@ public class TetheringTest { mTethering.interfaceRemoved(TEST_WLAN_IFNAME); mLooper.dispatchAll(); - verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME); - // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4. - verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME); - verify(mNMService, times(2)) - .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).stopTethering(); - verify(mNMService, times(1)).setIpForwardingEnabled(false); + verify(mNetd, times(1)).tetherApplyDnsInterfaces(); + verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME); + // interfaceSetCfg() called once for enabling and twice disabling IPv4. + verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, times(1)).tetherStop(); + verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME); verify(mWifiManager, times(3)).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); verifyNoMoreInteractions(mWifiManager); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. @@ -680,8 +688,8 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull()); @@ -690,7 +698,8 @@ public class TetheringTest { @Test public void workingMobileUsbTethering_IPv4LegacyDhcp() { - Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + true); sendConfigurationChanged(); final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); runUsbTethering(upstreamState); @@ -704,8 +713,8 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); @@ -717,8 +726,8 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mRouterAdvertisementDaemon, times(1)).start(); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); @@ -732,12 +741,11 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobile464xlatUpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, - TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); @@ -750,9 +758,9 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); // Then 464xlat comes up upstreamState = buildMobile464xlatUpstreamState(); @@ -768,20 +776,18 @@ public class TetheringTest { mLooper.dispatchAll(); // Forwarding is added for 464xlat - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, - TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); // Forwarding was not re-added for v6 (still times(1)) - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); // DHCP not restarted on downstream (still times(1)) verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); } @Test public void configTetherUpstreamAutomaticIgnoresConfigTetherUpstreamTypes() throws Exception { - when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic)) - .thenReturn(true); + when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true); sendConfigurationChanged(); // Setup IPv6 @@ -816,7 +822,7 @@ public class TetheringTest { mLooper.dispatchAll(); verify(mWifiManager, times(1)).startSoftAp(null); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Emulate externally-visible WifiManager effects, causing the // per-interface state machine to start up, and telling us that @@ -829,7 +835,7 @@ public class TetheringTest { verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); verifyNoMoreInteractions(mWifiManager); } @@ -843,7 +849,7 @@ public class TetheringTest { mLooper.dispatchAll(); verify(mWifiManager, times(1)).startSoftAp(null); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Emulate externally-visible WifiManager effects, causing the // per-interface state machine to start up, and telling us that @@ -854,9 +860,11 @@ public class TetheringTest { verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); - verify(mNMService, times(1)).setIpForwardingEnabled(true); - verify(mNMService, times(1)).startTethering(any(String[].class)); - verifyNoMoreInteractions(mNMService); + verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, times(1)).tetherStartWithConfiguration(any()); + verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME), + anyString(), anyString()); + verifyNoMoreInteractions(mNetd); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verify(mWifiManager).updateInterfaceIpState( @@ -874,8 +882,8 @@ public class TetheringTest { ///// // We do not currently emulate any upstream being found. // - // This is why there are no calls to verify mNMService.enableNat() or - // mNMService.startInterfaceForwarding(). + // This is why there are no calls to verify mNetd.tetherAddForward() or + // mNetd.ipfwdAddInterfaceForward(). ///// // Emulate pressing the WiFi tethering button. @@ -883,7 +891,7 @@ public class TetheringTest { mLooper.dispatchAll(); verify(mWifiManager, times(1)).stopSoftAp(); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Emulate externally-visible WifiManager effects, when tethering mode // is being torn down. @@ -891,16 +899,16 @@ public class TetheringTest { mTethering.interfaceRemoved(TEST_WLAN_IFNAME); mLooper.dispatchAll(); - verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME); - // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4. - verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME); - verify(mNMService, atLeastOnce()) - .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).stopTethering(); - verify(mNMService, times(1)).setIpForwardingEnabled(false); + verify(mNetd, times(1)).tetherApplyDnsInterfaces(); + verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME); + // interfaceSetCfg() called once for enabling and twice for disabling IPv4. + verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, times(1)).tetherStop(); + verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME); verify(mWifiManager, times(3)).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); verifyNoMoreInteractions(mWifiManager); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. @@ -911,14 +919,14 @@ public class TetheringTest { @Test public void failureEnablingIpForwarding() throws Exception { when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true); - doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true); + doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME); // Emulate pressing the WiFi tethering button. mTethering.startTethering(TETHERING_WIFI, null, false); mLooper.dispatchAll(); verify(mWifiManager, times(1)).startSoftAp(null); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Emulate externally-visible WifiManager effects, causing the // per-interface state machine to start up, and telling us that @@ -927,15 +935,15 @@ public class TetheringTest { sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); mLooper.dispatchAll(); - // We verify get/set called thrice here: twice for setup (on NMService) and once during - // teardown (on Netd) because all events happen over the course of the single + // We verify get/set called three times here: twice for setup and once during + // teardown because all events happen over the course of the single // dispatchAll() above. Note that once the IpServer IPv4 address config // code is refactored the two calls during shutdown will revert to one. - verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME); - verify(mNMService, times(2)) - .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class)); - verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName))); - verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME); + verify(mNetd, times(3)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName))); + verify(mNetd, times(1)).tetherInterfaceAdd(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME); + verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME), + anyString(), anyString()); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verify(mWifiManager).updateInterfaceIpState( @@ -945,18 +953,20 @@ public class TetheringTest { assertEquals(3, mTetheringDependencies.mIsTetheringSupportedCalls); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); // This is called, but will throw. - verify(mNMService, times(1)).setIpForwardingEnabled(true); + verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); // This never gets called because of the exception thrown above. - verify(mNMService, times(0)).startTethering(any(String[].class)); + verify(mNetd, times(0)).tetherStartWithConfiguration(any()); // When the master state machine transitions to an error state it tells // downstream interfaces, which causes us to tell Wi-Fi about the error // so it can take down AP mode. - verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).tetherApplyDnsInterfaces(); + verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); } private void runUserRestrictionsChange( @@ -1210,12 +1220,12 @@ public class TetheringTest { @Test public void testMultiSimAware() throws Exception { final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration(); - assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.subId); + assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.activeDataSubId); final int fakeSubId = 1234; mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId); final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration(); - assertEquals(fakeSubId, newConfig.subId); + assertEquals(fakeSubId, newConfig.activeDataSubId); } private void workingWifiP2pGroupOwner( @@ -1228,9 +1238,9 @@ public class TetheringTest { verifyInterfaceServingModeStarted(TEST_P2P_IFNAME); verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_AVAILABLE_TETHER); - verify(mNMService, times(1)).setIpForwardingEnabled(true); - verify(mNMService, times(1)).startTethering(any(String[].class)); - verifyNoMoreInteractions(mNMService); + verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, times(1)).tetherStartWithConfiguration(any()); + verifyNoMoreInteractions(mNetd); verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY); verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks(); // This will be called twice, one is on entering IpServer.STATE_AVAILABLE, @@ -1245,16 +1255,16 @@ public class TetheringTest { mTethering.interfaceRemoved(TEST_P2P_IFNAME); mLooper.dispatchAll(); - verify(mNMService, times(1)).untetherInterface(TEST_P2P_IFNAME); - // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4. - verify(mNMService, times(2)).getInterfaceConfig(TEST_P2P_IFNAME); - verify(mNMService, times(2)) - .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).stopTethering(); - verify(mNMService, times(1)).setIpForwardingEnabled(false); + verify(mNetd, times(1)).tetherApplyDnsInterfaces(); + verify(mNetd, times(1)).tetherInterfaceRemove(TEST_P2P_IFNAME); + verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME); + // interfaceSetCfg() called once for enabling and twice for disabling IPv4. + verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, times(1)).tetherStop(); + verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME); verify(mUpstreamNetworkMonitor, never()).getCurrentPreferredUpstream(); verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any()); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME)); @@ -1268,12 +1278,11 @@ public class TetheringTest { sendWifiP2pConnectionChanged(true, false, TEST_P2P_IFNAME); mLooper.dispatchAll(); - verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME); - verify(mNMService, never()) - .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME); - verify(mNMService, never()).setIpForwardingEnabled(true); - verify(mNMService, never()).startTethering(any(String[].class)); + verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, never()).tetherInterfaceAdd(TEST_P2P_IFNAME); + verify(mNetd, never()).networkAddInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME); + verify(mNetd, never()).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, never()).tetherStartWithConfiguration(any()); // Emulate externally-visible WifiP2pManager effects, when wifi p2p group // is being removed. @@ -1281,13 +1290,13 @@ public class TetheringTest { mTethering.interfaceRemoved(TEST_P2P_IFNAME); mLooper.dispatchAll(); - verify(mNMService, never()).untetherInterface(TEST_P2P_IFNAME); - verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME); - verify(mNMService, never()) - .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, never()).stopTethering(); - verify(mNMService, never()).setIpForwardingEnabled(false); - verifyNoMoreInteractions(mNMService); + verify(mNetd, never()).tetherApplyDnsInterfaces(); + verify(mNetd, never()).tetherInterfaceRemove(TEST_P2P_IFNAME); + verify(mNetd, never()).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME); + verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, never()).tetherStop(); + verify(mNetd, never()).ipfwdDisableForwarding(TETHERING_NAME); + verifyNoMoreInteractions(mNetd); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME)); @@ -1306,7 +1315,7 @@ public class TetheringTest { private void workingWifiP2pGroupOwnerLegacyMode( boolean emulateInterfaceStatusChanged) throws Exception { // change to legacy mode and update tethering information by chaning SIM - when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs)) + when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) .thenReturn(new String[]{}); final int fakeSubId = 1234; mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId); @@ -1317,12 +1326,11 @@ public class TetheringTest { sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME); mLooper.dispatchAll(); - verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME); - verify(mNMService, never()) - .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME); - verify(mNMService, never()).setIpForwardingEnabled(true); - verify(mNMService, never()).startTethering(any(String[].class)); + verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, never()).tetherInterfaceAdd(TEST_P2P_IFNAME); + verify(mNetd, never()).networkAddInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME); + verify(mNetd, never()).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, never()).tetherStartWithConfiguration(any()); assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME)); } @Test @@ -1345,6 +1353,50 @@ public class TetheringTest { workingWifiP2pGroupClient(false); } + private void setDataSaverEnabled(boolean enabled) { + final Intent intent = new Intent(ACTION_RESTRICT_BACKGROUND_CHANGED); + mServiceContext.sendBroadcastAsUser(intent, UserHandle.ALL); + + final int status = enabled ? RESTRICT_BACKGROUND_STATUS_ENABLED + : RESTRICT_BACKGROUND_STATUS_DISABLED; + when(mCm.getRestrictBackgroundStatus()).thenReturn(status); + mLooper.dispatchAll(); + } + + @Test + public void testDataSaverChanged() { + // Start Tethering. + final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); + runUsbTethering(upstreamState); + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + // Data saver is ON. + setDataSaverEnabled(true); + // Verify that tethering should be disabled. + verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE); + mTethering.interfaceRemoved(TEST_USB_IFNAME); + mLooper.dispatchAll(); + assertEquals(mTethering.getTetheredIfaces(), new String[0]); + reset(mUsbManager); + + runUsbTethering(upstreamState); + // Verify that user can start tethering again without turning OFF data saver. + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + + // If data saver is keep ON with change event, tethering should not be OFF this time. + setDataSaverEnabled(true); + verify(mUsbManager, times(0)).setCurrentFunctions(UsbManager.FUNCTION_NONE); + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + + // If data saver is turned OFF, it should not change tethering. + setDataSaverEnabled(false); + verify(mUsbManager, times(0)).setCurrentFunctions(UsbManager.FUNCTION_NONE); + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + } + + private static <T> void assertContains(Collection<T> collection, T element) { + assertTrue(element + " not found in " + collection, collection.contains(element)); + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java index c90abbbedb5f..5ed75bf26f8b 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java @@ -18,13 +18,14 @@ package com.android.server.connectivity.tethering; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; -import static android.net.ConnectivityManager.TYPE_NONE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.connectivity.tethering.UpstreamNetworkMonitor.TYPE_NONE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -538,13 +539,15 @@ public class UpstreamNetworkMonitorTest { mUNM.selectPreferredUpstreamType(preferredTypes)); verify(mEntitleMgr, times(1)).maybeRunProvisioning(); } + private void assertSatisfiesLegacyType(int legacyType, UpstreamNetworkState ns) { if (legacyType == TYPE_NONE) { assertTrue(ns == null); return; } - final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType); + final NetworkCapabilities nc = + UpstreamNetworkMonitor.networkCapabilitiesForType(legacyType); assertTrue(nc.satisfiedByNetworkCapabilities(ns.networkCapabilities)); } diff --git a/packages/WAPPushManager/Android.bp b/packages/WAPPushManager/Android.bp index c3913698022d..083dac944936 100644 --- a/packages/WAPPushManager/Android.bp +++ b/packages/WAPPushManager/Android.bp @@ -10,5 +10,5 @@ android_app { proguard_flags_files: ["proguard.flags"], }, - product_specific: true, + system_ext_specific: true, } diff --git a/packages/WAPPushManager/CleanSpec.mk b/packages/WAPPushManager/CleanSpec.mk index 2dcbb1034622..f4e316c56bbf 100644 --- a/packages/WAPPushManager/CleanSpec.mk +++ b/packages/WAPPushManager/CleanSpec.mk @@ -49,3 +49,5 @@ # ************************************************ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/WAPPushManager) +$(call add-clean-step, rm -rf $(TARGET_OUT_PRODUCT)/app/WAPPushManager) + diff --git a/packages/WallpaperCropper/Android.bp b/packages/WallpaperCropper/Android.bp index 40c423520081..ac38b271395c 100644 --- a/packages/WallpaperCropper/Android.bp +++ b/packages/WallpaperCropper/Android.bp @@ -3,7 +3,7 @@ android_app { srcs: ["src/**/*.java"], platform_apis: true, certificate: "platform", - product_specific: true, + system_ext_specific: true, privileged: true, optimize: { proguard_flags_files: ["proguard.flags"], diff --git a/packages/WallpaperCropper/CleanSpec.mk b/packages/WallpaperCropper/CleanSpec.mk index e6d8d5a774f1..f08c3430756a 100644 --- a/packages/WallpaperCropper/CleanSpec.mk +++ b/packages/WallpaperCropper/CleanSpec.mk @@ -44,6 +44,7 @@ #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/WallpaperCropper) +$(call add-clean-step, rm -rf $(TARGET_OUT_PRODUCT)/priv-app/WallpaperCropper) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java index b7e05d9c984c..7b5514b8a0d1 100644 --- a/rs/java/android/renderscript/BaseObj.java +++ b/rs/java/android/renderscript/BaseObj.java @@ -16,8 +16,10 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import dalvik.system.CloseGuard; + import java.util.concurrent.locks.ReentrantReadWriteLock; /** diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java index b8eb3a1d7a40..0941907d35f8 100644 --- a/rs/java/android/renderscript/Element.java +++ b/rs/java/android/renderscript/Element.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * <p>An Element represents one item within an {@link diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java index 9a6b0bcd4544..7cc2825ae565 100644 --- a/rs/java/android/renderscript/FileA3D.java +++ b/rs/java/android/renderscript/FileA3D.java @@ -16,13 +16,13 @@ package android.renderscript; -import java.io.File; -import java.io.InputStream; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.content.res.Resources; +import java.io.File; +import java.io.InputStream; + /** * @hide * @deprecated in API 16 diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java index 583350e91795..df9d8019f28d 100644 --- a/rs/java/android/renderscript/Font.java +++ b/rs/java/android/renderscript/Font.java @@ -16,17 +16,16 @@ package android.renderscript; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.os.Environment; + import java.io.File; import java.io.InputStream; import java.util.HashMap; import java.util.Map; -import android.os.Environment; - -import android.annotation.UnsupportedAppUsage; -import android.content.res.AssetManager; -import android.content.res.Resources; - /** * @hide * @deprecated in API 16 diff --git a/rs/java/android/renderscript/Matrix4f.java b/rs/java/android/renderscript/Matrix4f.java index 026c9fbd7d5e..a9469c979494 100644 --- a/rs/java/android/renderscript/Matrix4f.java +++ b/rs/java/android/renderscript/Matrix4f.java @@ -16,8 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; -import java.lang.Math; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java index 5321dcb957dc..826225a70d86 100644 --- a/rs/java/android/renderscript/Mesh.java +++ b/rs/java/android/renderscript/Mesh.java @@ -16,7 +16,8 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.Vector; /** diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java index e28d646f5f1c..ff072183e927 100644 --- a/rs/java/android/renderscript/Program.java +++ b/rs/java/android/renderscript/Program.java @@ -17,14 +17,14 @@ package android.renderscript; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.res.Resources; +import android.util.Log; + import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import android.annotation.UnsupportedAppUsage; -import android.content.res.Resources; -import android.util.Log; - /** * @hide diff --git a/rs/java/android/renderscript/ProgramFragment.java b/rs/java/android/renderscript/ProgramFragment.java index 3dde9b6d6400..880531207b4d 100644 --- a/rs/java/android/renderscript/ProgramFragment.java +++ b/rs/java/android/renderscript/ProgramFragment.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java index d05d41da8b6f..c741ce6e77ed 100644 --- a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java +++ b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramRaster.java b/rs/java/android/renderscript/ProgramRaster.java index 33000acb4eb0..a21696c82161 100644 --- a/rs/java/android/renderscript/ProgramRaster.java +++ b/rs/java/android/renderscript/ProgramRaster.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java index 622fe21be47a..7e61347ee218 100644 --- a/rs/java/android/renderscript/ProgramStore.java +++ b/rs/java/android/renderscript/ProgramStore.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramVertex.java b/rs/java/android/renderscript/ProgramVertex.java index 83d9ea7be645..9257234de42c 100644 --- a/rs/java/android/renderscript/ProgramVertex.java +++ b/rs/java/android/renderscript/ProgramVertex.java @@ -38,7 +38,7 @@ **/ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java index 579d3bb507e8..03c2eaf91242 100644 --- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java +++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/RSSurfaceView.java b/rs/java/android/renderscript/RSSurfaceView.java index 561373cef625..6bdde387b334 100644 --- a/rs/java/android/renderscript/RSSurfaceView.java +++ b/rs/java/android/renderscript/RSSurfaceView.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.AttributeSet; import android.view.SurfaceHolder; diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index f4c27771c846..46c49e5a5e11 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.AssetManager; import android.graphics.Bitmap; diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java index 1797bef4be8d..862d032d6987 100644 --- a/rs/java/android/renderscript/RenderScriptCacheDir.java +++ b/rs/java/android/renderscript/RenderScriptCacheDir.java @@ -16,7 +16,8 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.File; /** diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java index 6fac83e8c4a8..dafaf367364d 100644 --- a/rs/java/android/renderscript/RenderScriptGL.java +++ b/rs/java/android/renderscript/RenderScriptGL.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.SurfaceTexture; import android.view.Surface; diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java index 9ad9aea9d7aa..d1d3a7642382 100644 --- a/rs/java/android/renderscript/Script.java +++ b/rs/java/android/renderscript/Script.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.SparseArray; /** diff --git a/services/Android.bp b/services/Android.bp index 53d792d1033a..943e491393dd 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -111,7 +111,7 @@ droidstubs { srcs: [":services-sources"], installable: false, // TODO: remove the --hide options below - args: " --show-single-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" + + args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" + " --hide-annotation android.annotation.Hide" + " --hide-package com.google.android.startop.iorap" + " --hide ReferencesHidden" + @@ -121,6 +121,12 @@ droidstubs { "framework-all", ], visibility: ["//visibility:private"], + check_api: { + current: { + api_file: "api/current.txt", + removed_api_file: "api/removed.txt", + }, + }, } java_library { diff --git a/services/api/current.txt b/services/api/current.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/services/api/current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/api/removed.txt b/services/api/removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/services/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/core/Android.bp b/services/core/Android.bp index cbd095b3a045..4c569efe4c0a 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -27,8 +27,8 @@ java_library_static { "android.hardware.light-V2.0-java", "android.hardware.power-V1.0-java", "android.hardware.tv.cec-V1.0-java", + "android.hardware.vibrator-java", "app-compat-annotations", - "vintf-vibrator-java", "framework-tethering", ], diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index d16244167c62..bbb7c523bac9 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -2167,8 +2167,9 @@ class AlarmManagerService extends SystemService { @Override public long currentNetworkTimeMillis() { final NtpTrustedTime time = NtpTrustedTime.getInstance(getContext()); - if (time.hasCache()) { - return time.currentTimeMillis(); + NtpTrustedTime.TimeResult ntpResult = time.getCachedTimeResult(); + if (ntpResult != null) { + return ntpResult.currentTimeMillis(); } else { throw new ParcelableException(new DateTimeException("Missing NTP fix")); } diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java new file mode 100644 index 000000000000..31cd5d519d87 --- /dev/null +++ b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java @@ -0,0 +1,258 @@ +/* + * Copyright 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 com.android.server; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothProfile.ServiceListener; +import android.content.Context; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings; +import android.util.Log; +import android.widget.Toast; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; + +/** + * The BluetoothAirplaneModeListener handles system airplane mode change callback and checks + * whether we need to inform BluetoothManagerService on this change. + * + * The information of airplane mode turns on would not be passed to the BluetoothManagerService + * when Bluetooth is on and Bluetooth is in one of the following situations: + * 1. Bluetooth A2DP is connected. + * 2. Bluetooth Hearing Aid profile is connected. + */ +class BluetoothAirplaneModeListener { + private static final String TAG = "BluetoothAirplaneModeListener"; + @VisibleForTesting static final String TOAST_COUNT = "bluetooth_airplane_toast_count"; + + private static final int MSG_AIRPLANE_MODE_CHANGED = 0; + + @VisibleForTesting static final int MAX_TOAST_COUNT = 10; // 10 times + + private final BluetoothManagerService mBluetoothManager; + private final BluetoothAirplaneModeHandler mHandler; + private AirplaneModeHelper mAirplaneHelper; + + @VisibleForTesting int mToastCount = 0; + + BluetoothAirplaneModeListener(BluetoothManagerService service, Looper looper, Context context) { + mBluetoothManager = service; + + mHandler = new BluetoothAirplaneModeHandler(looper); + context.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true, + mAirplaneModeObserver); + } + + private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) { + @Override + public void onChange(boolean unused) { + // Post from system main thread to android_io thread. + Message msg = mHandler.obtainMessage(MSG_AIRPLANE_MODE_CHANGED); + mHandler.sendMessage(msg); + } + }; + + private class BluetoothAirplaneModeHandler extends Handler { + BluetoothAirplaneModeHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_AIRPLANE_MODE_CHANGED: + handleAirplaneModeChange(); + break; + default: + Log.e(TAG, "Invalid message: " + msg.what); + break; + } + } + } + + /** + * Call after boot complete + */ + @VisibleForTesting + void start(AirplaneModeHelper helper) { + Log.i(TAG, "start"); + mAirplaneHelper = helper; + mToastCount = mAirplaneHelper.getSettingsInt(TOAST_COUNT); + } + + @VisibleForTesting + boolean shouldPopToast() { + if (mToastCount >= MAX_TOAST_COUNT) { + return false; + } + mToastCount++; + mAirplaneHelper.setSettingsInt(TOAST_COUNT, mToastCount); + return true; + } + + @VisibleForTesting + void handleAirplaneModeChange() { + if (shouldSkipAirplaneModeChange()) { + Log.i(TAG, "Ignore airplane mode change"); + // We have to store Bluetooth state here, so if user turns off Bluetooth + // after airplane mode is turned on, we don't forget to turn on Bluetooth + // when airplane mode turns off. + mAirplaneHelper.setSettingsInt(Settings.Global.BLUETOOTH_ON, + BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); + if (shouldPopToast()) { + mAirplaneHelper.showToastMessage(); + } + return; + } + mAirplaneHelper.onAirplaneModeChanged(mBluetoothManager); + } + + @VisibleForTesting + boolean shouldSkipAirplaneModeChange() { + if (mAirplaneHelper == null) { + return false; + } + if (!mAirplaneHelper.isBluetoothOn() || !mAirplaneHelper.isAirplaneModeOn() + || !mAirplaneHelper.isA2dpOrHearingAidConnected()) { + return false; + } + return true; + } + + /** + * Helper class that handles callout and callback methods without + * complex logic. + */ + @VisibleForTesting + public static class AirplaneModeHelper { + private volatile BluetoothA2dp mA2dp; + private volatile BluetoothHearingAid mHearingAid; + private final BluetoothAdapter mAdapter; + private final Context mContext; + + AirplaneModeHelper(Context context) { + mAdapter = BluetoothAdapter.getDefaultAdapter(); + mContext = context; + + mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP); + mAdapter.getProfileProxy(mContext, mProfileServiceListener, + BluetoothProfile.HEARING_AID); + } + + private final ServiceListener mProfileServiceListener = new ServiceListener() { + @Override + public void onServiceConnected(int profile, BluetoothProfile proxy) { + // Setup Bluetooth profile proxies + switch (profile) { + case BluetoothProfile.A2DP: + mA2dp = (BluetoothA2dp) proxy; + break; + case BluetoothProfile.HEARING_AID: + mHearingAid = (BluetoothHearingAid) proxy; + break; + default: + break; + } + } + + @Override + public void onServiceDisconnected(int profile) { + // Clear Bluetooth profile proxies + switch (profile) { + case BluetoothProfile.A2DP: + mA2dp = null; + break; + case BluetoothProfile.HEARING_AID: + mHearingAid = null; + break; + default: + break; + } + } + }; + + @VisibleForTesting + public boolean isA2dpOrHearingAidConnected() { + return isA2dpConnected() || isHearingAidConnected(); + } + + @VisibleForTesting + public boolean isBluetoothOn() { + final BluetoothAdapter adapter = mAdapter; + if (adapter == null) { + return false; + } + return adapter.getLeState() == BluetoothAdapter.STATE_ON; + } + + @VisibleForTesting + public boolean isAirplaneModeOn() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) == 1; + } + + @VisibleForTesting + public void onAirplaneModeChanged(BluetoothManagerService managerService) { + managerService.onAirplaneModeChanged(); + } + + @VisibleForTesting + public int getSettingsInt(String name) { + return Settings.Global.getInt(mContext.getContentResolver(), + name, 0); + } + + @VisibleForTesting + public void setSettingsInt(String name, int value) { + Settings.Global.putInt(mContext.getContentResolver(), + name, value); + } + + @VisibleForTesting + public void showToastMessage() { + Resources r = mContext.getResources(); + final CharSequence text = r.getString( + R.string.bluetooth_airplane_mode_toast, 0); + Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); + } + + private boolean isA2dpConnected() { + final BluetoothA2dp a2dp = mA2dp; + if (a2dp == null) { + return false; + } + return a2dp.getConnectedDevices().size() > 0; + } + + private boolean isHearingAidConnected() { + final BluetoothHearingAid hearingAid = mHearingAid; + if (hearingAid == null) { + return false; + } + return hearingAid.getConnectedDevices().size() > 0; + } + }; +} diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index cdfd310a85ae..fa8eda54e53c 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -68,6 +68,7 @@ import android.util.Slog; import android.util.StatsLog; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.server.pm.UserRestrictionsUtils; @@ -138,7 +139,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // Bluetooth persisted setting is on // but Airplane mode will affect Bluetooth state at start up // and Airplane mode will have higher priority. - private static final int BLUETOOTH_ON_AIRPLANE = 2; + @VisibleForTesting + static final int BLUETOOTH_ON_AIRPLANE = 2; private static final int SERVICE_IBLUETOOTH = 1; private static final int SERVICE_IBLUETOOTHGATT = 2; @@ -159,6 +161,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private boolean mBinding; private boolean mUnbinding; + private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; + // used inside handler thread private boolean mQuietEnable = false; private boolean mEnable; @@ -257,68 +261,65 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } }; - private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) { - @Override - public void onChange(boolean unused) { - synchronized (this) { - if (isBluetoothPersistedStateOn()) { - if (isAirplaneModeOn()) { - persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); - } else { - persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); - } + public void onAirplaneModeChanged() { + synchronized (this) { + if (isBluetoothPersistedStateOn()) { + if (isAirplaneModeOn()) { + persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); + } else { + persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); } + } - int st = BluetoothAdapter.STATE_OFF; - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - st = mBluetooth.getState(); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call getState", e); - return; - } finally { - mBluetoothLock.readLock().unlock(); + int st = BluetoothAdapter.STATE_OFF; + try { + mBluetoothLock.readLock().lock(); + if (mBluetooth != null) { + st = mBluetooth.getState(); } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to call getState", e); + return; + } finally { + mBluetoothLock.readLock().unlock(); + } - Slog.d(TAG, - "Airplane Mode change - current state: " + BluetoothAdapter.nameForState( - st) + ", isAirplaneModeOn()=" + isAirplaneModeOn()); + Slog.d(TAG, + "Airplane Mode change - current state: " + BluetoothAdapter.nameForState( + st) + ", isAirplaneModeOn()=" + isAirplaneModeOn()); - if (isAirplaneModeOn()) { - // Clear registered LE apps to force shut-off - clearBleApps(); + if (isAirplaneModeOn()) { + // Clear registered LE apps to force shut-off + clearBleApps(); - // If state is BLE_ON make sure we trigger disableBLE - if (st == BluetoothAdapter.STATE_BLE_ON) { - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) { - addActiveLog( - BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, - mContext.getPackageName(), false); - mBluetooth.onBrEdrDown(); - mEnable = false; - mEnableExternal = false; - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onBrEdrDown", e); - } finally { - mBluetoothLock.readLock().unlock(); + // If state is BLE_ON make sure we trigger disableBLE + if (st == BluetoothAdapter.STATE_BLE_ON) { + try { + mBluetoothLock.readLock().lock(); + if (mBluetooth != null) { + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, + mContext.getPackageName(), false); + mBluetooth.onBrEdrDown(); + mEnable = false; + mEnableExternal = false; } - } else if (st == BluetoothAdapter.STATE_ON) { - sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, - mContext.getPackageName()); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to call onBrEdrDown", e); + } finally { + mBluetoothLock.readLock().unlock(); } - } else if (mEnableExternal) { - sendEnableMsg(mQuietEnableExternal, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, + } else if (st == BluetoothAdapter.STATE_ON) { + sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, mContext.getPackageName()); } + } else if (mEnableExternal) { + sendEnableMsg(mQuietEnableExternal, + BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, + mContext.getPackageName()); } } - }; + } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -430,9 +431,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS); if (airplaneModeRadios == null || airplaneModeRadios.contains( Settings.Global.RADIO_BLUETOOTH)) { - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true, - mAirplaneModeObserver); + mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener( + this, IoThread.get().getLooper(), context); } int systemUiUid = -1; @@ -478,6 +478,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return state != BLUETOOTH_OFF; } + private boolean isBluetoothPersistedStateOnAirplane() { + if (!supportBluetoothPersistedState()) { + return false; + } + int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1); + if (DBG) { + Slog.d(TAG, "Bluetooth persisted state: " + state); + } + return state == BLUETOOTH_ON_AIRPLANE; + } + /** * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH */ @@ -954,10 +965,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } synchronized (mReceiver) { - if (persist) { - persistBluetoothSetting(BLUETOOTH_OFF); + if (!isBluetoothPersistedStateOnAirplane()) { + if (persist) { + persistBluetoothSetting(BLUETOOTH_OFF); + } + mEnableExternal = false; } - mEnableExternal = false; sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName); } @@ -1185,6 +1198,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); mHandler.sendMessage(getMsg); } + if (mBluetoothAirplaneModeListener != null) { + mBluetoothAirplaneModeListener.start( + new BluetoothAirplaneModeListener.AirplaneModeHelper(mContext)); + } } /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index bb78aceb3b5f..76c119db0ad9 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -39,6 +39,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.uidRulesToString; @@ -86,14 +87,14 @@ import android.net.MatchAllNetworkSpecifier; import android.net.NattSocketKeepalive; import android.net.Network; import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkConfig; -import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkMisc; import android.net.NetworkMonitorManager; import android.net.NetworkPolicyManager; +import android.net.NetworkProvider; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkScore; @@ -221,6 +222,7 @@ import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicInteger; /** * @hide @@ -364,10 +366,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_PROXY_HAS_CHANGED = 16; /** - * used internally when registering NetworkFactories - * obj = NetworkFactoryInfo + * used internally when registering NetworkProviders + * obj = NetworkProviderInfo */ - private static final int EVENT_REGISTER_NETWORK_FACTORY = 17; + private static final int EVENT_REGISTER_NETWORK_PROVIDER = 17; /** * used internally when registering NetworkAgents @@ -403,10 +405,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_RELEASE_NETWORK_REQUEST = 22; /** - * used internally when registering NetworkFactories + * used internally when registering NetworkProviders * obj = Messenger */ - private static final int EVENT_UNREGISTER_NETWORK_FACTORY = 23; + private static final int EVENT_UNREGISTER_NETWORK_PROVIDER = 23; /** * used internally to expire a wakelock when transitioning @@ -597,6 +599,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // sequence number of NetworkRequests private int mNextNetworkRequestId = 1; + // Sequence number for NetworkProvider IDs. + private final AtomicInteger mNextNetworkProviderId = new AtomicInteger( + NetworkProvider.FIRST_PROVIDER_ID); + // NetworkRequest activity String log entries. private static final int MAX_NETWORK_REQUEST_LOGS = 20; private final LocalLog mNetworkRequestInfoLogs = new LocalLog(MAX_NETWORK_REQUEST_LOGS); @@ -1567,48 +1573,49 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); final int uid = Binder.getCallingUid(); NetworkState state = getUnfilteredActiveNetworkState(uid); - return state.linkProperties; + if (state.linkProperties == null) return null; + return linkPropertiesRestrictedForCallerPermissions(state.linkProperties, + Binder.getCallingPid(), uid); } @Override public LinkProperties getLinkPropertiesForType(int networkType) { enforceAccessPermission(); NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); - if (nai != null) { - synchronized (nai) { - return new LinkProperties(nai.linkProperties); - } - } - return null; + final LinkProperties lp = getLinkProperties(nai); + if (lp == null) return null; + return linkPropertiesRestrictedForCallerPermissions( + lp, Binder.getCallingPid(), Binder.getCallingUid()); } // TODO - this should be ALL networks @Override public LinkProperties getLinkProperties(Network network) { enforceAccessPermission(); - return getLinkProperties(getNetworkAgentInfoForNetwork(network)); + final LinkProperties lp = getLinkProperties(getNetworkAgentInfoForNetwork(network)); + if (lp == null) return null; + return linkPropertiesRestrictedForCallerPermissions( + lp, Binder.getCallingPid(), Binder.getCallingUid()); } - private LinkProperties getLinkProperties(NetworkAgentInfo nai) { + @Nullable + private LinkProperties getLinkProperties(@Nullable NetworkAgentInfo nai) { if (nai == null) { return null; } synchronized (nai) { - return new LinkProperties(nai.linkProperties); + return nai.linkProperties; } } private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) { - if (nai != null) { - synchronized (nai) { - if (nai.networkCapabilities != null) { - return networkCapabilitiesRestrictedForCallerPermissions( - nai.networkCapabilities, - Binder.getCallingPid(), Binder.getCallingUid()); - } - } + if (nai == null) return null; + synchronized (nai) { + if (nai.networkCapabilities == null) return null; + return networkCapabilitiesRestrictedForCallerPermissions( + nai.networkCapabilities, + Binder.getCallingPid(), Binder.getCallingUid()); } - return null; } @Override @@ -1630,6 +1637,29 @@ public class ConnectivityService extends IConnectivityManager.Stub return newNc; } + private LinkProperties linkPropertiesRestrictedForCallerPermissions( + LinkProperties lp, int callerPid, int callerUid) { + if (lp == null) return new LinkProperties(); + + // Only do a permission check if sanitization is needed, to avoid unnecessary binder calls. + final boolean needsSanitization = + (lp.getCaptivePortalApiUrl() != null || lp.getCaptivePortalData() != null); + if (!needsSanitization) { + return new LinkProperties(lp); + } + + if (checkSettingsPermission(callerPid, callerUid)) { + return lp.makeSensitiveFieldsParcelingCopy(); + } + + final LinkProperties newLp = new LinkProperties(lp); + // Sensitive fields would not be parceled anyway, but sanitize for consistency before the + // object gets parceled. + newLp.setCaptivePortalApiUrl(null); + newLp.setCaptivePortalData(null); + return newLp; + } + private void restrictRequestUidsForCaller(NetworkCapabilities nc) { if (!checkSettingsPermission()) { nc.setSingleUid(Binder.getCallingUid()); @@ -2381,9 +2411,9 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } - pw.print("NetworkFactories for:"); - for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - pw.print(" " + nfi.name); + pw.print("NetworkProviders for:"); + for (NetworkProviderInfo npi : mNetworkProviderInfos.values()) { + pw.print(" " + npi.name); } pw.println(); pw.println(); @@ -2618,8 +2648,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai.everConnected) { loge("ERROR: cannot call explicitlySelected on already-connected network"); } - nai.networkMisc.explicitlySelected = toBool(msg.arg1); - nai.networkMisc.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2); + nai.networkAgentConfig.explicitlySelected = toBool(msg.arg1); + nai.networkAgentConfig.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2); // Mark the network as temporarily accepting partial connectivity so that it // will be validated (and possibly become default) even if it only provides // partial internet access. Note that if user connects to partial connectivity @@ -2627,7 +2657,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // out of wifi coverage) and if the same wifi is available again, the device // will auto connect to this wifi even though the wifi has "no internet". // TODO: Evaluate using a separate setting in IpMemoryStore. - nai.networkMisc.acceptPartialConnectivity = toBool(msg.arg2); + nai.networkAgentConfig.acceptPartialConnectivity = toBool(msg.arg2); break; } case NetworkAgent.EVENT_SOCKET_KEEPALIVE: { @@ -2659,10 +2689,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } // Only show the notification when the private DNS is broken and the // PRIVATE_DNS_BROKEN notification hasn't shown since last valid. - if (privateDnsBroken && !nai.networkMisc.hasShownBroken) { + if (privateDnsBroken && !nai.networkAgentConfig.hasShownBroken) { showNetworkNotification(nai, NotificationType.PRIVATE_DNS_BROKEN); } - nai.networkMisc.hasShownBroken = privateDnsBroken; + nai.networkAgentConfig.hasShownBroken = privateDnsBroken; } else if (nai.networkCapabilities.isPrivateDnsBroken()) { // If probePrivateDnsCompleted is false but nai.networkCapabilities says // private DNS is broken, it means this network is being reevaluated. @@ -2672,7 +2702,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.networkCapabilities.setPrivateDnsBroken(false); final int oldScore = nai.getCurrentScore(); updateCapabilities(oldScore, nai, nai.networkCapabilities); - nai.networkMisc.hasShownBroken = false; + nai.networkAgentConfig.hasShownBroken = false; } break; } @@ -2714,7 +2744,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.lastValidated = valid; nai.everValidated |= valid; updateCapabilities(oldScore, nai, nai.networkCapabilities); - // If score has changed, rebroadcast to NetworkFactories. b/17726566 + // If score has changed, rebroadcast to NetworkProviders. b/17726566 if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai); if (valid) { handleFreshlyValidatedNetwork(nai); @@ -2731,7 +2761,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // If network becomes valid, the hasShownBroken should be reset for // that network so that the notification will be fired when the private // DNS is broken again. - nai.networkMisc.hasShownBroken = false; + nai.networkAgentConfig.hasShownBroken = false; } } else if (partialConnectivityChanged) { updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities); @@ -2790,9 +2820,10 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor"); break; } - if (!nai.networkMisc.provisioningNotificationDisabled) { + if (!nai.networkAgentConfig.provisioningNotificationDisabled) { mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null, - (PendingIntent) msg.obj, nai.networkMisc.explicitlySelected); + (PendingIntent) msg.obj, + nai.networkAgentConfig.explicitlySelected); } } break; @@ -2829,25 +2860,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; } - private boolean maybeHandleNetworkFactoryMessage(Message msg) { - switch (msg.what) { - default: - return false; - case NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: { - handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.sendingUid, - /* callOnUnavailable */ true); - break; - } - } - return true; - } - @Override public void handleMessage(Message msg) { if (!maybeHandleAsyncChannelMessage(msg) && !maybeHandleNetworkMonitorMessage(msg) - && !maybeHandleNetworkAgentInfoMessage(msg) - && !maybeHandleNetworkFactoryMessage(msg)) { + && !maybeHandleNetworkAgentInfoMessage(msg)) { maybeHandleNetworkAgentMessage(msg); } } @@ -3018,32 +3035,16 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleAsyncChannelHalfConnect(Message msg) { ensureRunningOnConnectivityServiceThread(); final AsyncChannel ac = (AsyncChannel) msg.obj; - if (mNetworkFactoryInfos.containsKey(msg.replyTo)) { + if (mNetworkProviderInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); // Finish setting up the full connection - mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage( - AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - // A network factory has connected. Send it all current NetworkRequests. - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - if (nri.request.isListen()) continue; - ensureRunningOnConnectivityServiceThread(); - NetworkAgentInfo nai = nri.mSatisfier; - final int score; - final int serial; - if (nai != null) { - score = nai.getCurrentScore(); - serial = nai.factorySerialNumber; - } else { - score = 0; - serial = NetworkFactory.SerialNumber.NONE; - } - ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial, - nri.request); - } + NetworkProviderInfo npi = mNetworkProviderInfos.get(msg.replyTo); + npi.completeConnection(); + sendAllRequestsToProvider(npi); } else { loge("Error connecting NetworkFactory"); - mNetworkFactoryInfos.remove(msg.obj); + mNetworkProviderInfos.remove(msg.obj); } } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { @@ -3075,8 +3076,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai != null) { disconnectAndDestroyNetwork(nai); } else { - NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(msg.replyTo); - if (DBG && nfi != null) log("unregisterNetworkFactory for " + nfi.name); + NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo); + if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name); } } @@ -3159,7 +3160,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it // after we've rematched networks with requests which should make a potential // fallback network the default or requested a new network from the - // NetworkFactories, so network traffic isn't interrupted for an unnecessarily + // NetworkProviders, so network traffic isn't interrupted for an unnecessarily // long time. destroyNativeNetwork(nai); mDnsManager.removeNetwork(nai.network); @@ -3172,8 +3173,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // This should never fail. Specifying an already in use NetID will cause failure. if (networkAgent.isVPN()) { mNetd.networkCreateVpn(networkAgent.network.netId, - (networkAgent.networkMisc == null - || !networkAgent.networkMisc.allowBypass)); + (networkAgent.networkAgentConfig == null + || !networkAgent.networkAgentConfig.allowBypass)); } else { mNetd.networkCreatePhysical(networkAgent.network.netId, getNetworkPermission(networkAgent.networkCapabilities)); @@ -3422,9 +3423,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, - nri.request); + for (NetworkProviderInfo npi : mNetworkProviderInfos.values()) { + npi.cancelRequest(nri.request); } } else { // listens don't have a singular affectedNetwork. Check all networks to see @@ -3474,16 +3474,16 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } - if (!nai.networkMisc.explicitlySelected) { + if (!nai.networkAgentConfig.explicitlySelected) { Slog.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network"); } - if (accept != nai.networkMisc.acceptUnvalidated) { - nai.networkMisc.acceptUnvalidated = accept; + if (accept != nai.networkAgentConfig.acceptUnvalidated) { + nai.networkAgentConfig.acceptUnvalidated = accept; // If network becomes partial connectivity and user already accepted to use this // network, we should respect the user's option and don't need to popup the // PARTIAL_CONNECTIVITY notification to user again. - nai.networkMisc.acceptPartialConnectivity = accept; + nai.networkAgentConfig.acceptPartialConnectivity = accept; rematchAllNetworksAndRequests(); sendUpdatedScoreToFactories(nai); } @@ -3520,8 +3520,8 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } - if (accept != nai.networkMisc.acceptPartialConnectivity) { - nai.networkMisc.acceptPartialConnectivity = accept; + if (accept != nai.networkAgentConfig.acceptPartialConnectivity) { + nai.networkAgentConfig.acceptPartialConnectivity = accept; } // TODO: Use the current design or save the user choice into IpMemoryStore. @@ -3619,14 +3619,29 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceSettingsPermission(); } + final NetworkMonitorManager nm = getNetworkMonitorManager(mNetwork); + if (nm == null) return; + nm.notifyCaptivePortalAppFinished(response); + } + + @Override + public void appRequest(final int request) { + final NetworkMonitorManager nm = getNetworkMonitorManager(mNetwork); + if (nm == null) return; + + if (request == CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED) { + nm.forceReevaluation(Binder.getCallingUid()); + } + } + + @Nullable + private NetworkMonitorManager getNetworkMonitorManager(final Network network) { // getNetworkAgentInfoForNetwork is thread-safe - final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(mNetwork); - if (nai == null) return; + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai == null) return null; // nai.networkMonitor() is thread-safe - final NetworkMonitorManager nm = nai.networkMonitor(); - if (nm == null) return; - nm.notifyCaptivePortalAppFinished(response); + return nai.networkMonitor(); } @Override @@ -3731,7 +3746,7 @@ public class ConnectivityService extends IConnectivityManager.Stub action = ConnectivityManager.ACTION_PROMPT_PARTIAL_CONNECTIVITY; // Don't bother the user with a high-priority notification if the network was not // explicitly selected by the user. - highPriority = nai.networkMisc.explicitlySelected; + highPriority = nai.networkAgentConfig.explicitlySelected; break; default: Slog.wtf(TAG, "Unknown notification type " + type); @@ -3764,14 +3779,15 @@ public class ConnectivityService extends IConnectivityManager.Stub // automatically connects to a network that has partial Internet access, the user will // always be able to use it, either because they've already chosen "don't ask again" or // because we have prompt them. - if (nai.partialConnectivity && !nai.networkMisc.acceptPartialConnectivity) { + if (nai.partialConnectivity && !nai.networkAgentConfig.acceptPartialConnectivity) { return true; } // If a network has no Internet access, only prompt if the network was explicitly selected // and if the user has not already told us to use the network regardless of whether it // validated or not. - if (nai.networkMisc.explicitlySelected && !nai.networkMisc.acceptUnvalidated) { + if (nai.networkAgentConfig.explicitlySelected + && !nai.networkAgentConfig.acceptUnvalidated) { return true; } @@ -3859,12 +3875,12 @@ public class ConnectivityService extends IConnectivityManager.Stub handleApplyDefaultProxy((ProxyInfo)msg.obj); break; } - case EVENT_REGISTER_NETWORK_FACTORY: { - handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj); + case EVENT_REGISTER_NETWORK_PROVIDER: { + handleRegisterNetworkProvider((NetworkProviderInfo) msg.obj); break; } - case EVENT_UNREGISTER_NETWORK_FACTORY: { - handleUnregisterNetworkFactory((Messenger)msg.obj); + case EVENT_UNREGISTER_NETWORK_PROVIDER: { + handleUnregisterNetworkProvider((Messenger) msg.obj); break; } case EVENT_REGISTER_NETWORK_AGENT: { @@ -4909,7 +4925,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } }; - private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos = new HashMap<>(); + private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>(); private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>(); private static final int MAX_NETWORK_REQUESTS_PER_UID = 100; @@ -4917,18 +4933,73 @@ public class ConnectivityService extends IConnectivityManager.Stub @GuardedBy("mUidToNetworkRequestCount") private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray(); - private static class NetworkFactoryInfo { + private static class NetworkProviderInfo { public final String name; public final Messenger messenger; - public final AsyncChannel asyncChannel; - public final int factorySerialNumber; + private final AsyncChannel mAsyncChannel; + private final IBinder.DeathRecipient mDeathRecipient; + public final int providerId; - NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel, - int factorySerialNumber) { + NetworkProviderInfo(String name, Messenger messenger, AsyncChannel asyncChannel, + int providerId, IBinder.DeathRecipient deathRecipient) { this.name = name; this.messenger = messenger; - this.asyncChannel = asyncChannel; - this.factorySerialNumber = factorySerialNumber; + this.providerId = providerId; + mAsyncChannel = asyncChannel; + mDeathRecipient = deathRecipient; + + if ((mAsyncChannel == null) == (mDeathRecipient == null)) { + throw new AssertionError("Must pass exactly one of asyncChannel or deathRecipient"); + } + } + + boolean isLegacyNetworkFactory() { + return mAsyncChannel != null; + } + + void sendMessageToNetworkProvider(int what, int arg1, int arg2, Object obj) { + try { + messenger.send(Message.obtain(null /* handler */, what, arg1, arg2, obj)); + } catch (RemoteException e) { + // Remote process died. Ignore; the death recipient will remove this + // NetworkProviderInfo from mNetworkProviderInfos. + } + } + + void requestNetwork(NetworkRequest request, int score, int servingProviderId) { + if (isLegacyNetworkFactory()) { + mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, + servingProviderId, request); + } else { + sendMessageToNetworkProvider(NetworkProvider.CMD_REQUEST_NETWORK, score, + servingProviderId, request); + } + } + + void cancelRequest(NetworkRequest request) { + if (isLegacyNetworkFactory()) { + mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request); + } else { + sendMessageToNetworkProvider(NetworkProvider.CMD_CANCEL_REQUEST, 0, 0, request); + } + } + + void connect(Context context, Handler handler) { + if (isLegacyNetworkFactory()) { + mAsyncChannel.connect(context, handler, messenger); + } else { + try { + messenger.getBinder().linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + mDeathRecipient.binderDied(); + } + } + } + + void completeConnection() { + if (isLegacyNetworkFactory()) { + mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + } } } @@ -5299,6 +5370,11 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri)); } + /** Returns the next Network provider ID. */ + public final int nextNetworkProviderId() { + return mNextNetworkProviderId.getAndIncrement(); + } + @Override public void releaseNetworkRequest(NetworkRequest networkRequest) { ensureNetworkRequestHasType(networkRequest); @@ -5309,31 +5385,65 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public int registerNetworkFactory(Messenger messenger, String name) { enforceNetworkFactoryPermission(); - NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(), - NetworkFactory.SerialNumber.nextSerialNumber()); - mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); - return nfi.factorySerialNumber; + NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger, new AsyncChannel(), + nextNetworkProviderId(), null /* deathRecipient */); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi)); + return npi.providerId; + } + + private void handleRegisterNetworkProvider(NetworkProviderInfo npi) { + if (mNetworkProviderInfos.containsKey(npi.messenger)) { + // Avoid creating duplicates. even if an app makes a direct AIDL call. + // This will never happen if an app calls ConnectivityManager#registerNetworkProvider, + // as that will throw if a duplicate provider is registered. + Slog.e(TAG, "Attempt to register existing NetworkProviderInfo " + + mNetworkProviderInfos.get(npi.messenger).name); + return; + } + + if (DBG) log("Got NetworkProvider Messenger for " + npi.name); + mNetworkProviderInfos.put(npi.messenger, npi); + npi.connect(mContext, mTrackerHandler); + if (!npi.isLegacyNetworkFactory()) { + // Legacy NetworkFactories get their requests when their AsyncChannel connects. + sendAllRequestsToProvider(npi); + } } - private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) { - if (DBG) log("Got NetworkFactory Messenger for " + nfi.name); - mNetworkFactoryInfos.put(nfi.messenger, nfi); - nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger); + @Override + public int registerNetworkProvider(Messenger messenger, String name) { + enforceNetworkFactoryPermission(); + NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger, + null /* asyncChannel */, nextNetworkProviderId(), + () -> unregisterNetworkProvider(messenger)); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi)); + return npi.providerId; } @Override - public void unregisterNetworkFactory(Messenger messenger) { + public void unregisterNetworkProvider(Messenger messenger) { enforceNetworkFactoryPermission(); - mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger)); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_PROVIDER, messenger)); } - private void handleUnregisterNetworkFactory(Messenger messenger) { - NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger); - if (nfi == null) { - loge("Failed to find Messenger in unregisterNetworkFactory"); + @Override + public void unregisterNetworkFactory(Messenger messenger) { + unregisterNetworkProvider(messenger); + } + + private void handleUnregisterNetworkProvider(Messenger messenger) { + NetworkProviderInfo npi = mNetworkProviderInfos.remove(messenger); + if (npi == null) { + loge("Failed to find Messenger in unregisterNetworkProvider"); return; } - if (DBG) log("unregisterNetworkFactory for " + nfi.name); + if (DBG) log("unregisterNetworkProvider for " + npi.name); + } + + @Override + public void declareNetworkRequestUnfulfillable(NetworkRequest request) { + enforceNetworkFactoryPermission(); + mHandler.post(() -> handleReleaseNetworkRequest(request, Binder.getCallingUid(), true)); } // NOTE: Accessed on multiple threads, must be synchronized on itself. @@ -5397,11 +5507,14 @@ public class ConnectivityService extends IConnectivityManager.Stub // changes that would conflict throughout the automerger graph. Having this method temporarily // helps with the process of going through with all these dependent changes across the entire // tree. - public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + /** + * Register a new agent. {@see #registerNetworkAgent} below. + */ + public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, - int currentScore, NetworkMisc networkMisc) { + int currentScore, NetworkAgentConfig networkAgentConfig) { return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities, - currentScore, networkMisc, NetworkFactory.SerialNumber.NONE); + currentScore, networkAgentConfig, NetworkProvider.ID_NONE); } /** @@ -5416,12 +5529,13 @@ public class ConnectivityService extends IConnectivityManager.Stub * later : see {@link #updateCapabilities}. * @param currentScore the initial score of the network. See * {@link NetworkAgentInfo#getCurrentScore}. - * @param networkMisc metadata about the network. This is never updated. - * @param factorySerialNumber the serial number of the factory owning this NetworkAgent. + * @param networkAgentConfig metadata about the network. This is never updated. + * @param providerId the ID of the provider owning this NetworkAgent. + * @return the network created for this agent. */ - public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, - int currentScore, NetworkMisc networkMisc, int factorySerialNumber) { + int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) { enforceNetworkFactoryPermission(); LinkProperties lp = new LinkProperties(linkProperties); @@ -5433,8 +5547,8 @@ public class ConnectivityService extends IConnectivityManager.Stub ns.putIntExtension(NetworkScore.LEGACY_SCORE, currentScore); final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc, - ns, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, - mDnsResolver, mNMS, factorySerialNumber); + ns, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), this, + mNetd, mDnsResolver, mNMS, providerId); // Make sure the network capabilities reflect what the agent info says. nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc)); final String extraInfo = networkInfo.getExtraInfo(); @@ -5452,7 +5566,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // If the network disconnects or sends any other event before that, messages are deferred by // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the // registration. - return nai.network.netId; + return nai.network; } private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { @@ -5704,6 +5818,19 @@ public class ConnectivityService extends IConnectivityManager.Stub return INetd.PERMISSION_NONE; } + private void updateNetworkPermissions(@NonNull final NetworkAgentInfo nai, + @NonNull final NetworkCapabilities newNc) { + final int oldPermission = getNetworkPermission(nai.networkCapabilities); + final int newPermission = getNetworkPermission(newNc); + if (oldPermission != newPermission && nai.created && !nai.isVPN()) { + try { + mNMS.setNetworkPermission(nai.network.netId, newPermission); + } catch (RemoteException e) { + loge("Exception in setNetworkPermission: " + e); + } + } + } + /** * Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are * maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal, @@ -5713,7 +5840,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Once a NetworkAgent is connected, complain if some immutable capabilities are removed. // Don't complain for VPNs since they're not driven by requests and there is no risk of // causing a connect/teardown loop. - // TODO: remove this altogether and make it the responsibility of the NetworkFactories to + // TODO: remove this altogether and make it the responsibility of the NetworkProviders to // avoid connect/teardown loops. if (nai.everConnected && !nai.isVPN() && @@ -5744,11 +5871,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { newNc.addCapability(NET_CAPABILITY_FOREGROUND); } - if (nai.isSuspended()) { - newNc.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); - } else { - newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED); - } if (nai.partialConnectivity) { newNc.addCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY); } else { @@ -5756,6 +5878,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } newNc.setPrivateDnsBroken(nai.networkCapabilities.isPrivateDnsBroken()); + // TODO : remove this once all factories are updated to send NOT_SUSPENDED and NOT_ROAMING + if (!newNc.hasTransport(TRANSPORT_CELLULAR)) { + newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + newNc.addCapability(NET_CAPABILITY_NOT_ROAMING); + } + return newNc; } @@ -5775,21 +5903,11 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param nai the network having its capabilities updated. * @param nc the new network capabilities. */ - private void updateCapabilities(int oldScore, NetworkAgentInfo nai, NetworkCapabilities nc) { + private void updateCapabilities(final int oldScore, @NonNull final NetworkAgentInfo nai, + @NonNull final NetworkCapabilities nc) { NetworkCapabilities newNc = mixInCapabilities(nai, nc); - if (Objects.equals(nai.networkCapabilities, newNc)) return; - - final int oldPermission = getNetworkPermission(nai.networkCapabilities); - final int newPermission = getNetworkPermission(newNc); - if (oldPermission != newPermission && nai.created && !nai.isVPN()) { - try { - mNMS.setNetworkPermission(nai.network.netId, newPermission); - } catch (RemoteException e) { - loge("Exception in setNetworkPermission: " + e); - } - } - + updateNetworkPermissions(nai, newNc); final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc); updateUids(nai, prevNc, newNc); @@ -5800,6 +5918,19 @@ public class ConnectivityService extends IConnectivityManager.Stub // on this network. We might have been called by rematchNetworkAndRequests when a // network changed foreground state. processListenRequests(nai); + final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED); + final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED); + final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING); + final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING); + if (prevSuspended != suspended || prevRoaming != roaming) { + // TODO (b/73132094) : remove this call once the few users of onSuspended and + // onResumed have been removed. + notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED + : ConnectivityManager.CALLBACK_RESUMED); + // updateNetworkInfo will mix in the suspended info from the capabilities and + // take appropriate action for the network having possibly changed state. + updateNetworkInfo(nai, nai.networkInfo); + } } else { // If the requestable capabilities have changed or the score changed, we can't have been // called by rematchNetworkAndRequests, so it's safe to start a rematch. @@ -5807,6 +5938,9 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); } + // TODO : static analysis indicates that prevNc can't be null here (getAndSetNetworkCaps + // never returns null), so mark the relevant members and functions in nai as @NonNull and + // remove this test if (prevNc != null) { final boolean oldMetered = prevNc.isMetered(); final boolean newMetered = newNc.isMetered(); @@ -5855,7 +5989,7 @@ public class ConnectivityService extends IConnectivityManager.Stub LinkProperties lp) { if (nc == null || lp == null) return false; return nai.isVPN() - && !nai.networkMisc.allowBypass + && !nai.networkAgentConfig.allowBypass && nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID && lp.getInterfaceName() != null && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()); @@ -5953,9 +6087,27 @@ public class ConnectivityService extends IConnectivityManager.Stub if (VDBG || DDBG){ log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); } - for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, - serial, networkRequest); + for (NetworkProviderInfo npi : mNetworkProviderInfos.values()) { + npi.requestNetwork(networkRequest, score, serial); + } + } + + /** Sends all current NetworkRequests to the specified factory. */ + private void sendAllRequestsToProvider(NetworkProviderInfo npi) { + ensureRunningOnConnectivityServiceThread(); + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + if (nri.request.isListen()) continue; + NetworkAgentInfo nai = nri.mSatisfier; + final int score; + final int serial; + if (nai != null) { + score = nai.getCurrentScore(); + serial = nai.factorySerialNumber; + } else { + score = 0; + serial = NetworkProvider.ID_NONE; + } + npi.requestNetwork(nri.request, score, serial); } } @@ -6010,7 +6162,8 @@ public class ConnectivityService extends IConnectivityManager.Stub case ConnectivityManager.CALLBACK_AVAILABLE: { putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions( networkAgent.networkCapabilities, nri.mPid, nri.mUid)); - putParcelable(bundle, new LinkProperties(networkAgent.linkProperties)); + putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions( + networkAgent.linkProperties, nri.mPid, nri.mUid)); // For this notification, arg1 contains the blocked status. msg.arg1 = arg1; break; @@ -6027,7 +6180,8 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case ConnectivityManager.CALLBACK_IP_CHANGED: { - putParcelable(bundle, new LinkProperties(networkAgent.linkProperties)); + putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions( + networkAgent.linkProperties, nri.mPid, nri.mUid)); break; } case ConnectivityManager.CALLBACK_BLK_CHANGED: { @@ -6136,6 +6290,30 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + // An accumulator class to gather the list of changes that result from a rematch. + // TODO : enrich to represent an entire set of changes to apply. + private static class NetworkReassignment { + static class NetworkBgStatePair { + @NonNull final NetworkAgentInfo mNetwork; + final boolean mOldBackground; + NetworkBgStatePair(@NonNull final NetworkAgentInfo network, + final boolean oldBackground) { + mNetwork = network; + mOldBackground = oldBackground; + } + } + + @NonNull private final Set<NetworkBgStatePair> mRematchedNetworks = new ArraySet<>(); + + @NonNull Iterable<NetworkBgStatePair> getRematchedNetworks() { + return mRematchedNetworks; + } + + void addRematchedNetwork(@NonNull final NetworkBgStatePair network) { + mRematchedNetworks.add(network); + } + } + private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork( @NonNull final NetworkAgentInfo newNetwork) { final int score = newNetwork.getCurrentScore(); @@ -6181,8 +6359,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // needed. A network is needed if it is the best network for // one or more NetworkRequests, or if it is a VPN. // - // - Tears down newNetwork if it just became validated - // but turns out to be unneeded. + // - Writes into the passed reassignment object all changes that should be done for + // rematching this network with all requests, to be applied later. // // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy, // it does not remove NetworkRequests that other Networks could better satisfy. @@ -6190,15 +6368,22 @@ public class ConnectivityService extends IConnectivityManager.Stub // This function should be used when possible instead of {@code rematchAllNetworksAndRequests} // as it performs better by a factor of the number of Networks. // + // TODO : stop writing to the passed reassignment. This is temporarily more useful, but + // it's unidiomatic Java and it's hard to read. + // + // @param changes a currently-building list of changes to write to // @param newNetwork is the network to be matched against NetworkRequests. // @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime(); - private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) { + private void rematchNetworkAndRequests(@NonNull final NetworkReassignment changes, + @NonNull final NetworkAgentInfo newNetwork, final long now) { ensureRunningOnConnectivityServiceThread(); if (!newNetwork.everConnected) return; boolean isNewDefault = false; NetworkAgentInfo oldDefaultNetwork = null; - final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork(); + changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork, + newNetwork.isBackgroundNetwork())); + final int score = newNetwork.getCurrentScore(); if (VDBG || DDBG) log("rematching " + newNetwork.name()); @@ -6236,11 +6421,11 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request); } addedRequests.add(nri); - // Tell NetworkFactories about the new score, so they can stop + // Tell NetworkProviders about the new score, so they can stop // trying to connect if they know they cannot match it. // TODO - this could get expensive if we have a lot of requests for this // network. Think about if there is a way to reduce this. Push - // netid->request mapping to each factory? + // netid->request mapping to each provider? sendUpdatedScoreToFactories(nri.request, newSatisfier); if (isDefaultRequest(nri)) { isNewDefault = true; @@ -6269,7 +6454,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " + newNetwork.name() + - " without updating mSatisfier or factories!"); + " without updating mSatisfier or providers!"); } // TODO: Technically, sending CALLBACK_LOST here is // incorrect if there is a replacement network currently @@ -6301,39 +6486,12 @@ public class ConnectivityService extends IConnectivityManager.Stub if (newNetwork.getCurrentScore() != score) { Slog.wtf(TAG, String.format( "BUG: %s changed score during rematch: %d -> %d", - newNetwork.name(), score, newNetwork.getCurrentScore())); + newNetwork.name(), score, newNetwork.getCurrentScore())); } // Notify requested networks are available after the default net is switched, but // before LegacyTypeTracker sends legacy broadcasts for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri); - - // Finally, process listen requests and update capabilities if the background state has - // changed for this network. For consistency with previous behavior, send onLost callbacks - // before onAvailable. - processNewlyLostListenRequests(newNetwork); - - // Maybe the network changed background states. Update its capabilities. - final boolean backgroundChanged = wasBackgroundNetwork != newNetwork.isBackgroundNetwork(); - if (backgroundChanged) { - final NetworkCapabilities newNc = mixInCapabilities(newNetwork, - newNetwork.networkCapabilities); - - final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities); - final int newPermission = getNetworkPermission(newNc); - if (oldPermission != newPermission) { - try { - mNMS.setNetworkPermission(newNetwork.network.netId, newPermission); - } catch (RemoteException e) { - loge("Exception in setNetworkPermission: " + e); - } - } - - newNetwork.getAndSetNetworkCapabilities(newNc); - notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED); - } - - processNewlySatisfiedListenRequests(newNetwork); } /** @@ -6355,12 +6513,24 @@ public class ConnectivityService extends IConnectivityManager.Stub // scoring network and then a higher scoring network, which could produce multiple // callbacks. Arrays.sort(nais); + final NetworkReassignment changes = new NetworkReassignment(); for (final NetworkAgentInfo nai : nais) { - rematchNetworkAndRequests(nai, now); + rematchNetworkAndRequests(changes, nai, now); } final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork(); + for (final NetworkReassignment.NetworkBgStatePair event : changes.getRematchedNetworks()) { + // Process listen requests and update capabilities if the background state has + // changed for this network. For consistency with previous behavior, send onLost + // callbacks before onAvailable. + processNewlyLostListenRequests(event.mNetwork); + if (event.mOldBackground != event.mNetwork.isBackgroundNetwork()) { + applyBackgroundChangeForRematch(event.mNetwork); + } + processNewlySatisfiedListenRequests(event.mNetwork); + } + for (final NetworkAgentInfo nai : nais) { // Rematching may have altered the linger state of some networks, so update all linger // timers. updateLingerState reads the state from the network agent and does nothing @@ -6392,6 +6562,24 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + /** + * Apply a change in background state resulting from rematching networks with requests. + * + * During rematch, a network may change background states by starting to satisfy or stopping + * to satisfy a foreground request. Listens don't count for this. When a network changes + * background states, its capabilities need to be updated and callbacks fired for the + * capability change. + * + * @param nai The network that changed background states + */ + private void applyBackgroundChangeForRematch(@NonNull final NetworkAgentInfo nai) { + final NetworkCapabilities newNc = mixInCapabilities(nai, nai.networkCapabilities); + if (Objects.equals(nai.networkCapabilities, newNc)) return; + updateNetworkPermissions(nai, newNc); + nai.getAndSetNetworkCapabilities(newNc); + notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); + } + private void updateLegacyTypeTrackerAndVpnLockdownForRematch( @Nullable final NetworkAgentInfo oldDefaultNetwork, @Nullable final NetworkAgentInfo newDefaultNetwork, @@ -6483,10 +6671,31 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) { + @NonNull + private NetworkInfo mixInInfo(@NonNull final NetworkAgentInfo nai, @NonNull NetworkInfo info) { + final NetworkInfo newInfo = new NetworkInfo(info); + // The suspended and roaming bits are managed in NetworkCapabilities. + final boolean suspended = + !nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_SUSPENDED); + if (suspended && info.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) { + // Only override the state with SUSPENDED if the network is currently in CONNECTED + // state. This is because the network could have been suspended before connecting, + // or it could be disconnecting while being suspended, and in both these cases + // the state should not be overridden. Note that the only detailed state that + // maps to State.CONNECTED is DetailedState.CONNECTED, so there is also no need to + // worry about multiple different substates of CONNECTED. + newInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, info.getReason(), + info.getExtraInfo()); + } + newInfo.setRoaming(!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + return newInfo; + } + + private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo info) { + final NetworkInfo newInfo = mixInInfo(networkAgent, info); + final NetworkInfo.State state = newInfo.getState(); NetworkInfo oldInfo = null; - final int oldScore = networkAgent.getCurrentScore(); synchronized (networkAgent) { oldInfo = networkAgent.networkInfo; networkAgent.networkInfo = newInfo; @@ -6528,7 +6737,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // command must be sent after updating LinkProperties to maximize chances of // NetworkMonitor seeing the correct LinkProperties when starting. // TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call. - if (networkAgent.networkMisc.acceptPartialConnectivity) { + if (networkAgent.networkAgentConfig.acceptPartialConnectivity) { networkAgent.networkMonitor().setAcceptPartialConnectivity(); } networkAgent.networkMonitor().notifyNetworkConnected( @@ -6568,17 +6777,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } else if (networkAgent.created && (oldInfo.getState() == NetworkInfo.State.SUSPENDED || state == NetworkInfo.State.SUSPENDED)) { - // going into or coming out of SUSPEND: re-score and notify - if (networkAgent.getCurrentScore() != oldScore) { - rematchAllNetworksAndRequests(); - } - updateCapabilities(networkAgent.getCurrentScore(), networkAgent, - networkAgent.networkCapabilities); - // TODO (b/73132094) : remove this call once the few users of onSuspended and - // onResumed have been removed. - notifyNetworkCallbacks(networkAgent, (state == NetworkInfo.State.SUSPENDED ? - ConnectivityManager.CALLBACK_SUSPENDED : - ConnectivityManager.CALLBACK_RESUMED)); mLegacyTypeTracker.update(networkAgent); } } diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java index 9dead161390f..aeb3e7fd94de 100644 --- a/services/core/java/com/android/server/DropBoxManagerService.java +++ b/services/core/java/com/android/server/DropBoxManagerService.java @@ -41,7 +41,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; -import android.text.format.Time; +import android.text.format.TimeMigrationUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -582,11 +582,9 @@ public final class DropBoxManagerService extends SystemService { } int numFound = 0, numArgs = searchArgs.size(); - Time time = new Time(); out.append("\n"); for (EntryFile entry : mAllFiles.contents) { - time.set(entry.timestampMillis); - String date = time.format("%Y-%m-%d %H:%M:%S"); + String date = TimeMigrationUtils.formatMillisWithFixedFormat(entry.timestampMillis); boolean match = true; for (int i = 0; i < numArgs && match; i++) { String arg = searchArgs.get(i); diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index 7909e3096cbe..c60460fccb76 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -44,9 +44,9 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements private static final String TAG = "DynamicSystemService"; private static final String NO_SERVICE_ERROR = "no gsiservice"; private static final int GSID_ROUGH_TIMEOUT_MS = 8192; - private static final String PATH_DEFAULT = "/data/gsi"; + private static final String PATH_DEFAULT = "/data/gsi/"; private Context mContext; - private String mInstallPath; + private String mInstallPath, mDsuSlot; private volatile IGsiService mGsiService; DynamicSystemService(Context context) { @@ -115,7 +115,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements } @Override - public boolean startInstallation() throws RemoteException { + public boolean startInstallation(String dsuSlot) throws RemoteException { IGsiService service = getGsiService(); // priority from high to low: sysprop -> sdcard -> /data String path = SystemProperties.get("os.aot.path"); @@ -129,16 +129,17 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue; File sdCard = volume.getPathFile(); if (sdCard.isDirectory()) { - path = sdCard.getPath(); + path = new File(sdCard, dsuSlot).getPath(); break; } } if (path.isEmpty()) { - path = PATH_DEFAULT; + path = PATH_DEFAULT + dsuSlot; } Slog.i(TAG, "startInstallation -> " + path); } mInstallPath = path; + mDsuSlot = dsuSlot; if (service.openInstall(path) != 0) { Slog.i(TAG, "Failed to open " + path); return false; @@ -203,7 +204,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException { IGsiService gsiService = getGsiService(); if (enable) { - return gsiService.enableGsi(oneShot) == 0; + return gsiService.enableGsi(oneShot, mDsuSlot) == 0; } else { return gsiService.disableGsi(); } diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index c0f10a3c86e1..9b1326bc88d7 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; + import android.Manifest; import android.app.AppOpsManager; import android.app.PendingIntent; @@ -37,6 +39,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.service.carrier.CarrierMessagingService; import android.telephony.SmsManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Slog; @@ -137,11 +140,6 @@ public class MmsServiceBroker extends SystemService { } @Override - public Bundle getCarrierConfigValues(int subId) throws RemoteException { - return null; - } - - @Override public Uri importTextMessage(String callingPkg, String address, int type, String text, long timestampMillis, boolean seen, boolean read) throws RemoteException { return null; @@ -370,12 +368,6 @@ public class MmsServiceBroker extends SystemService { } @Override - public Bundle getCarrierConfigValues(int subId) throws RemoteException { - Slog.d(TAG, "getCarrierConfigValues() by " + getCallingPackageName()); - return getServiceGuarded().getCarrierConfigValues(subId); - } - - @Override public Uri importTextMessage(String callingPkg, String address, int type, String text, long timestampMillis, boolean seen, boolean read) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), @@ -523,11 +515,11 @@ public class MmsServiceBroker extends SystemService { // Grant permission for the carrier app. Intent intent = new Intent(action); - TelephonyManager telephonyManager = - (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - List<String> carrierPackages = - telephonyManager.getCarrierPackageNamesForIntentAndPhone( - intent, SubscriptionManager.getPhoneId(subId)); + TelephonyManager telephonyManager = (TelephonyManager) + mContext.getSystemService(Context.TELEPHONY_SERVICE); + List<String> carrierPackages = telephonyManager + .getCarrierPackageNamesForIntentAndPhone( + intent, getPhoneIdFromSubId(subId)); if (carrierPackages != null && carrierPackages.size() == 1) { LocalServices.getService(UriGrantsManagerInternal.class) .grantUriPermissionFromIntent(callingUid, carrierPackages.get(0), @@ -539,4 +531,13 @@ public class MmsServiceBroker extends SystemService { return contentUri; } } + + private int getPhoneIdFromSubId(int subId) { + SubscriptionManager subManager = (SubscriptionManager) + mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + if (subManager == null) return INVALID_SIM_SLOT_INDEX; + SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId); + if (info == null) return INVALID_SIM_SLOT_INDEX; + return info.getSimSlotIndex(); + } } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 0d496b6b427d..1daed1b54683 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -58,10 +58,12 @@ import android.net.NetworkStack; import android.net.NetworkStats; import android.net.NetworkUtils; import android.net.RouteInfo; -import android.net.TetherConfigParcel; import android.net.TetherStatsParcel; import android.net.UidRange; import android.net.UidRangeParcel; +import android.net.shared.NetdUtils; +import android.net.shared.RouteUtils; +import android.net.shared.RouteUtils.ModifyOperation; import android.net.util.NetdService; import android.os.BatteryStats; import android.os.Binder; @@ -897,48 +899,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void addRoute(int netId, RouteInfo route) { - modifyRoute(MODIFY_OPERATION_ADD, netId, route); + NetworkStack.checkNetworkStackPermission(mContext); + RouteUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route); } @Override public void removeRoute(int netId, RouteInfo route) { - modifyRoute(MODIFY_OPERATION_REMOVE, netId, route); - } - - private void modifyRoute(boolean add, int netId, RouteInfo route) { NetworkStack.checkNetworkStackPermission(mContext); - - final String ifName = route.getInterface(); - final String dst = route.getDestination().toString(); - final String nextHop; - - switch (route.getType()) { - case RouteInfo.RTN_UNICAST: - if (route.hasGateway()) { - nextHop = route.getGateway().getHostAddress(); - } else { - nextHop = INetd.NEXTHOP_NONE; - } - break; - case RouteInfo.RTN_UNREACHABLE: - nextHop = INetd.NEXTHOP_UNREACHABLE; - break; - case RouteInfo.RTN_THROW: - nextHop = INetd.NEXTHOP_THROW; - break; - default: - nextHop = INetd.NEXTHOP_NONE; - break; - } - try { - if (add) { - mNetdService.networkAddRoute(netId, ifName, dst, nextHop); - } else { - mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop); - } - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } + RouteUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route); } private ArrayList<String> readRouteList(String filename) { @@ -1022,12 +990,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) { NetworkStack.checkNetworkStackPermission(mContext); - // an odd number of addrs will fail try { - final TetherConfigParcel config = new TetherConfigParcel(); - config.usingLegacyDnsProxy = usingLegacyDnsProxy; - config.dhcpRanges = dhcpRange; - mNetdService.tetherStartWithConfiguration(config); + NetdUtils.tetherStart(mNetdService, usingLegacyDnsProxy, dhcpRange); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); } @@ -1059,26 +1023,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub { public void tetherInterface(String iface) { NetworkStack.checkNetworkStackPermission(mContext); try { - mNetdService.tetherInterfaceAdd(iface); + final LinkAddress addr = getInterfaceConfig(iface).getLinkAddress(); + final IpPrefix dest = new IpPrefix(addr.getAddress(), addr.getPrefixLength()); + NetdUtils.tetherInterface(mNetdService, iface, dest); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); } - List<RouteInfo> routes = new ArrayList<>(); - // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it - // suitable to use as a route destination. - routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface)); - addInterfaceToLocalNetwork(iface, routes); } @Override public void untetherInterface(String iface) { NetworkStack.checkNetworkStackPermission(mContext); try { - mNetdService.tetherInterfaceRemove(iface); + NetdUtils.untetherInterface(mNetdService, iface); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); - } finally { - removeInterfaceFromLocalNetwork(iface); } } @@ -2121,16 +2080,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) { modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface); - - for (RouteInfo route : routes) { - if (!route.isDefaultRoute()) { - modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, route); - } - } - - // IPv6 link local should be activated always. - modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, - new RouteInfo(new IpPrefix("fe80::/64"), null, iface)); + // modifyInterfaceInNetwork already check calling permission. + RouteUtils.addRoutesToLocalNetwork(mNetdService, iface, routes); } @Override @@ -2140,17 +2091,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public int removeRoutesFromLocalNetwork(List<RouteInfo> routes) { - int failures = 0; - - for (RouteInfo route : routes) { - try { - modifyRoute(MODIFY_OPERATION_REMOVE, INetd.LOCAL_NET_ID, route); - } catch (IllegalStateException e) { - failures++; - } - } - - return failures; + NetworkStack.checkNetworkStackPermission(mContext); + return RouteUtils.removeRoutesFromLocalNetwork(mNetdService, routes); } @Override diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index 9a7a4e79ab33..2fb1f7783814 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -54,7 +54,6 @@ import android.provider.Settings.Global; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.IntArray; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -527,7 +526,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub { @Override public void accept(INetworkScoreCache networkScoreCache, Object cookie) { - int filterType = NetworkScoreManager.CACHE_FILTER_NONE; + int filterType = NetworkScoreManager.SCORE_FILTER_NONE; if (cookie instanceof Integer) { filterType = (Integer) cookie; } @@ -551,17 +550,17 @@ public class NetworkScoreService extends INetworkScoreService.Stub { private List<ScoredNetwork> filterScores(List<ScoredNetwork> scoredNetworkList, int filterType) { switch (filterType) { - case NetworkScoreManager.CACHE_FILTER_NONE: + case NetworkScoreManager.SCORE_FILTER_NONE: return scoredNetworkList; - case NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK: + case NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK: if (mCurrentNetworkFilter == null) { mCurrentNetworkFilter = new CurrentNetworkScoreCacheFilter(new WifiInfoSupplier(mContext)); } return mCurrentNetworkFilter.apply(scoredNetworkList); - case NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS: + case NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS: if (mScanResultsFilter == null) { mScanResultsFilter = new ScanResultsScoreCacheFilter( new ScanResultsSupplier(mContext)); diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index 1ff455ea7a8f..c34dd984f865 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -16,15 +16,273 @@ package com.android.server; -import android.os.IBinder; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.app.timedetector.NetworkTimeSuggestion; +import android.app.timedetector.TimeDetector; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.SystemClock; +import android.os.TimestampedValue; +import android.provider.Settings; +import android.util.Log; +import android.util.NtpTrustedTime; +import android.util.TimeUtils; + +import com.android.internal.util.DumpUtils; + +import java.io.FileDescriptor; +import java.io.PrintWriter; /** - * An interface for NetworkTimeUpdateService implementations. Eventually part or all of this service - * will be subsumed into {@link com.android.server.timedetector.TimeDetectorService}. In the - * meantime this interface allows Android to use either the old or new implementation. + * Monitors the network time. If looking up the network time fails for some reason, it tries a few + * times with a short interval and then resets to checking on longer intervals. + * + * <p>When available, the time is always suggested to the {@link + * com.android.server.timedetector.TimeDetectorService} where it may be used to set the device + * system clock, depending on user settings and what other signals are available. */ -public interface NetworkTimeUpdateService extends IBinder { +public class NetworkTimeUpdateService extends Binder { + + private static final String TAG = "NetworkTimeUpdateService"; + private static final boolean DBG = false; + + private static final int EVENT_AUTO_TIME_ENABLED = 1; + private static final int EVENT_POLL_NETWORK_TIME = 2; + private static final int EVENT_NETWORK_CHANGED = 3; + + private static final String ACTION_POLL = + "com.android.server.NetworkTimeUpdateService.action.POLL"; + + private static final int POLL_REQUEST = 0; + + private Network mDefaultNetwork = null; + + private final Context mContext; + private final NtpTrustedTime mTime; + private final AlarmManager mAlarmManager; + private final TimeDetector mTimeDetector; + private final ConnectivityManager mCM; + private final PendingIntent mPendingPollIntent; + private final PowerManager.WakeLock mWakeLock; + + // NTP lookup is done on this thread and handler + private Handler mHandler; + private AutoTimeSettingObserver mAutoTimeSettingObserver; + private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback; + + // Normal polling frequency + private final long mPollingIntervalMs; + // Try-again polling interval, in case the network request failed + private final long mPollingIntervalShorterMs; + // Number of times to try again + private final int mTryAgainTimesMax; + // Keeps track of how many quick attempts were made to fetch NTP time. + // During bootup, the network may not have been up yet, or it's taking time for the + // connection to happen. + private int mTryAgainCounter; + + public NetworkTimeUpdateService(Context context) { + mContext = context; + mTime = NtpTrustedTime.getInstance(context); + mAlarmManager = mContext.getSystemService(AlarmManager.class); + mTimeDetector = mContext.getSystemService(TimeDetector.class); + mCM = mContext.getSystemService(ConnectivityManager.class); + + Intent pollIntent = new Intent(ACTION_POLL, null); + mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); + + mPollingIntervalMs = mContext.getResources().getInteger( + com.android.internal.R.integer.config_ntpPollingInterval); + mPollingIntervalShorterMs = mContext.getResources().getInteger( + com.android.internal.R.integer.config_ntpPollingIntervalShorter); + mTryAgainTimesMax = mContext.getResources().getInteger( + com.android.internal.R.integer.config_ntpRetry); + + mWakeLock = context.getSystemService(PowerManager.class).newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, TAG); + } /** Initialize the receivers and initiate the first NTP request */ - void systemRunning(); + public void systemRunning() { + registerForAlarms(); + + HandlerThread thread = new HandlerThread(TAG); + thread.start(); + mHandler = new MyHandler(thread.getLooper()); + mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback(); + mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler); + + mAutoTimeSettingObserver = new AutoTimeSettingObserver(mContext, mHandler, + EVENT_AUTO_TIME_ENABLED); + mAutoTimeSettingObserver.observe(); + } + + private void registerForAlarms() { + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); + } + }, new IntentFilter(ACTION_POLL)); + } + + private void onPollNetworkTime(int event) { + // If we don't have any default network, don't bother. + if (mDefaultNetwork == null) return; + mWakeLock.acquire(); + try { + onPollNetworkTimeUnderWakeLock(event); + } finally { + mWakeLock.release(); + } + } + + private void onPollNetworkTimeUnderWakeLock(int event) { + // Force an NTP fix when outdated + NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult(); + if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) { + if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); + mTime.forceRefresh(); + cachedNtpResult = mTime.getCachedTimeResult(); + } + + if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) { + // Obtained fresh fix; schedule next normal update + resetAlarm(mPollingIntervalMs); + + // Suggest the time to the time detector. It may choose use it to set the system clock. + TimestampedValue<Long> timeSignal = new TimestampedValue<>( + cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis()); + NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); + timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateService. event=" + event); + mTimeDetector.suggestNetworkTime(timeSuggestion); + } else { + // No fresh fix; schedule retry + mTryAgainCounter++; + if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { + resetAlarm(mPollingIntervalShorterMs); + } else { + // Try much later + mTryAgainCounter = 0; + resetAlarm(mPollingIntervalMs); + } + } + } + + /** + * Cancel old alarm and starts a new one for the specified interval. + * + * @param interval when to trigger the alarm, starting from now. + */ + private void resetAlarm(long interval) { + mAlarmManager.cancel(mPendingPollIntent); + long now = SystemClock.elapsedRealtime(); + long next = now + interval; + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent); + } + + /** Handler to do the network accesses on */ + private class MyHandler extends Handler { + + MyHandler(Looper l) { + super(l); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_AUTO_TIME_ENABLED: + case EVENT_POLL_NETWORK_TIME: + case EVENT_NETWORK_CHANGED: + onPollNetworkTime(msg.what); + break; + } + } + } + + private class NetworkTimeUpdateCallback extends NetworkCallback { + @Override + public void onAvailable(Network network) { + Log.d(TAG, String.format("New default network %s; checking time.", network)); + mDefaultNetwork = network; + // Running on mHandler so invoke directly. + onPollNetworkTime(EVENT_NETWORK_CHANGED); + } + + @Override + public void onLost(Network network) { + if (network.equals(mDefaultNetwork)) mDefaultNetwork = null; + } + } + + /** + * Observer to watch for changes to the AUTO_TIME setting. It only triggers when the setting + * is enabled. + */ + private static class AutoTimeSettingObserver extends ContentObserver { + + private final Context mContext; + private final int mMsg; + private final Handler mHandler; + + AutoTimeSettingObserver(Context context, Handler handler, int msg) { + super(handler); + mContext = context; + mHandler = handler; + mMsg = msg; + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME), + false, this); + } + + @Override + public void onChange(boolean selfChange) { + if (isAutomaticTimeEnabled()) { + mHandler.obtainMessage(mMsg).sendToTarget(); + } + } + + /** + * Checks if the user prefers to automatically set the time. + */ + private boolean isAutomaticTimeEnabled() { + ContentResolver resolver = mContext.getContentResolver(); + return Settings.Global.getInt(resolver, Settings.Global.AUTO_TIME, 0) != 0; + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + pw.print("PollingIntervalMs: "); + TimeUtils.formatDuration(mPollingIntervalMs, pw); + pw.print("\nPollingIntervalShorterMs: "); + TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); + pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); + pw.println("\nTryAgainCounter: " + mTryAgainCounter); + NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult(); + pw.println("NTP cache result: " + ntpResult); + if (ntpResult != null) { + pw.println("NTP result age: " + ntpResult.getAgeMillis()); + } + pw.println(); + } } diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java deleted file mode 100644 index 39be311e902d..000000000000 --- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.database.ContentObserver; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.SystemClock; -import android.provider.Settings; -import android.telephony.TelephonyManager; -import android.util.Log; -import android.util.NtpTrustedTime; -import android.util.TimeUtils; - -import com.android.internal.util.DumpUtils; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Monitors the network time and updates the system time if it is out of sync - * and there hasn't been any NITZ update from the carrier recently. - * If looking up the network time fails for some reason, it tries a few times with a short - * interval and then resets to checking on longer intervals. - * <p> - * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't - * available. - * </p> - */ -public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeUpdateService { - - private static final String TAG = "NetworkTimeUpdateService"; - private static final boolean DBG = false; - - private static final int EVENT_AUTO_TIME_CHANGED = 1; - private static final int EVENT_POLL_NETWORK_TIME = 2; - private static final int EVENT_NETWORK_CHANGED = 3; - - private static final String ACTION_POLL = - "com.android.server.NetworkTimeUpdateService.action.POLL"; - - private static final int POLL_REQUEST = 0; - - private static final long NOT_SET = -1; - private long mNitzTimeSetTime = NOT_SET; - private Network mDefaultNetwork = null; - - private final Context mContext; - private final NtpTrustedTime mTime; - private final AlarmManager mAlarmManager; - private final ConnectivityManager mCM; - private final PendingIntent mPendingPollIntent; - private final PowerManager.WakeLock mWakeLock; - - // NTP lookup is done on this thread and handler - private Handler mHandler; - private SettingsObserver mSettingsObserver; - private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback; - - // Normal polling frequency - private final long mPollingIntervalMs; - // Try-again polling interval, in case the network request failed - private final long mPollingIntervalShorterMs; - // Number of times to try again - private final int mTryAgainTimesMax; - // If the time difference is greater than this threshold, then update the time. - private final int mTimeErrorThresholdMs; - // Keeps track of how many quick attempts were made to fetch NTP time. - // During bootup, the network may not have been up yet, or it's taking time for the - // connection to happen. - private int mTryAgainCounter; - - public NetworkTimeUpdateServiceImpl(Context context) { - mContext = context; - mTime = NtpTrustedTime.getInstance(context); - mAlarmManager = mContext.getSystemService(AlarmManager.class); - mCM = mContext.getSystemService(ConnectivityManager.class); - - Intent pollIntent = new Intent(ACTION_POLL, null); - mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); - - mPollingIntervalMs = mContext.getResources().getInteger( - com.android.internal.R.integer.config_ntpPollingInterval); - mPollingIntervalShorterMs = mContext.getResources().getInteger( - com.android.internal.R.integer.config_ntpPollingIntervalShorter); - mTryAgainTimesMax = mContext.getResources().getInteger( - com.android.internal.R.integer.config_ntpRetry); - mTimeErrorThresholdMs = mContext.getResources().getInteger( - com.android.internal.R.integer.config_ntpThreshold); - - mWakeLock = context.getSystemService(PowerManager.class).newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, TAG); - } - - @Override - public void systemRunning() { - registerForTelephonyIntents(); - registerForAlarms(); - - HandlerThread thread = new HandlerThread(TAG); - thread.start(); - mHandler = new MyHandler(thread.getLooper()); - mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback(); - mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler); - - mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED); - mSettingsObserver.observe(mContext); - } - - private void registerForTelephonyIntents() { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(TelephonyManager.ACTION_NETWORK_SET_TIME); - mContext.registerReceiver(mNitzReceiver, intentFilter); - } - - private void registerForAlarms() { - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); - } - }, new IntentFilter(ACTION_POLL)); - } - - private void onPollNetworkTime(int event) { - // If Automatic time is not set, don't bother. Similarly, if we don't - // have any default network, don't bother. - if (mDefaultNetwork == null) return; - mWakeLock.acquire(); - try { - onPollNetworkTimeUnderWakeLock(event); - } finally { - mWakeLock.release(); - } - } - - private void onPollNetworkTimeUnderWakeLock(int event) { - // Force an NTP fix when outdated - if (mTime.getCacheAge() >= mPollingIntervalMs) { - if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); - mTime.forceRefresh(); - } - - if (mTime.getCacheAge() < mPollingIntervalMs) { - // Obtained fresh fix; schedule next normal update - resetAlarm(mPollingIntervalMs); - if (isAutomaticTimeRequested()) { - updateSystemClock(event); - } - - } else { - // No fresh fix; schedule retry - mTryAgainCounter++; - if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { - resetAlarm(mPollingIntervalShorterMs); - } else { - // Try much later - mTryAgainCounter = 0; - resetAlarm(mPollingIntervalMs); - } - } - } - - private long getNitzAge() { - if (mNitzTimeSetTime == NOT_SET) { - return Long.MAX_VALUE; - } else { - return SystemClock.elapsedRealtime() - mNitzTimeSetTime; - } - } - - /** - * Consider updating system clock based on current NTP fix, if requested by - * user, significant enough delta, and we don't have a recent NITZ. - */ - private void updateSystemClock(int event) { - final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED); - if (!forceUpdate) { - if (getNitzAge() < mPollingIntervalMs) { - if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ"); - return; - } - - final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis()); - if (skew < mTimeErrorThresholdMs) { - if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew"); - return; - } - } - - SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis()); - } - - /** - * Cancel old alarm and starts a new one for the specified interval. - * - * @param interval when to trigger the alarm, starting from now. - */ - private void resetAlarm(long interval) { - mAlarmManager.cancel(mPendingPollIntent); - long now = SystemClock.elapsedRealtime(); - long next = now + interval; - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent); - } - - /** - * Checks if the user prefers to automatically set the time. - */ - private boolean isAutomaticTimeRequested() { - return Settings.Global.getInt( - mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0; - } - - /** Receiver for Nitz time events */ - private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (DBG) Log.d(TAG, "Received " + action); - if (TelephonyManager.ACTION_NETWORK_SET_TIME.equals(action)) { - mNitzTimeSetTime = SystemClock.elapsedRealtime(); - } - } - }; - - /** Handler to do the network accesses on */ - private class MyHandler extends Handler { - - public MyHandler(Looper l) { - super(l); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_AUTO_TIME_CHANGED: - case EVENT_POLL_NETWORK_TIME: - case EVENT_NETWORK_CHANGED: - onPollNetworkTime(msg.what); - break; - } - } - } - - private class NetworkTimeUpdateCallback extends NetworkCallback { - @Override - public void onAvailable(Network network) { - Log.d(TAG, String.format("New default network %s; checking time.", network)); - mDefaultNetwork = network; - // Running on mHandler so invoke directly. - onPollNetworkTime(EVENT_NETWORK_CHANGED); - } - - @Override - public void onLost(Network network) { - if (network.equals(mDefaultNetwork)) mDefaultNetwork = null; - } - } - - /** Observer to watch for changes to the AUTO_TIME setting */ - private static class SettingsObserver extends ContentObserver { - - private int mMsg; - private Handler mHandler; - - SettingsObserver(Handler handler, int msg) { - super(handler); - mHandler = handler; - mMsg = msg; - } - - void observe(Context context) { - ContentResolver resolver = context.getContentResolver(); - resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME), - false, this); - } - - @Override - public void onChange(boolean selfChange) { - mHandler.obtainMessage(mMsg).sendToTarget(); - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; - pw.print("PollingIntervalMs: "); - TimeUtils.formatDuration(mPollingIntervalMs, pw); - pw.print("\nPollingIntervalShorterMs: "); - TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); - pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); - pw.print("TimeErrorThresholdMs: "); - TimeUtils.formatDuration(mTimeErrorThresholdMs, pw); - pw.println("\nTryAgainCounter: " + mTryAgainCounter); - pw.println("NTP cache age: " + mTime.getCacheAge()); - pw.println("NTP cache certainty: " + mTime.getCacheCertainty()); - pw.println(); - } -} diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index d1bc6af88347..90b0c11cc8dd 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2648,9 +2648,11 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public boolean supportsCheckpoint() throws RemoteException { - // Only the system process is permitted to start checkpoints - if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { - throw new SecurityException("no permission to check filesystem checkpoint support"); + // Only the root, system_server and shell processes are permitted to start checkpoints + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID + && callingUid != Process.SHELL_UID) { + throw new SecurityException("no permission to start filesystem checkpoint"); } return mVold.supportsCheckpoint(); @@ -2665,8 +2667,10 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public void startCheckpoint(int numTries) throws RemoteException { - // Only the system process is permitted to start checkpoints - if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { + // Only the root, system_server and shell processes are permitted to start checkpoints + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID + && callingUid != Process.SHELL_UID) { throw new SecurityException("no permission to start filesystem checkpoint"); } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index b5ecd196ba8a..62743aac55f6 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -16,12 +16,15 @@ package com.android.server; +import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_DATA; import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_VOICE; import static java.util.Arrays.copyOf; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.BroadcastReceiver; @@ -44,8 +47,16 @@ import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; import android.telephony.CallAttributes; import android.telephony.CallQuality; +import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.CellLocation; +import android.telephony.CellSignalStrength; +import android.telephony.CellSignalStrengthCdma; +import android.telephony.CellSignalStrengthGsm; +import android.telephony.CellSignalStrengthLte; +import android.telephony.CellSignalStrengthNr; +import android.telephony.CellSignalStrengthTdscdma; +import android.telephony.CellSignalStrengthWcdma; import android.telephony.DataFailCause; import android.telephony.DisconnectCause; import android.telephony.LocationAccessPolicy; @@ -57,6 +68,7 @@ import android.telephony.PreciseDisconnectCause; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; @@ -95,7 +107,7 @@ import java.util.NoSuchElementException; * and 15973975 by saving the phoneId of the registrant and then using the * phoneId when deciding to to make a callback. This is necessary because * a subId changes from to a dummy value when a SIM is removed and thus won't - * compare properly. Because SubscriptionManager.getPhoneId(int subId) handles + * compare properly. Because getPhoneIdFromSubId(int subId) handles * the dummy value conversion we properly do the callbacks. * * Eventually we may want to remove the notion of dummy value but for now this @@ -112,6 +124,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { Context context; String callingPackage; + String callingFeatureId; IBinder binder; @@ -128,7 +141,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; + int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; boolean matchPhoneStateListenerEvent(int events) { return (callback != null) && ((events & this.events) != 0); @@ -145,7 +158,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { boolean canReadCallLog() { try { return TelephonyPermissions.checkReadCallLog( - context, subId, callerPid, callerUid, callingPackage); + context, subId, callerPid, callerUid, callingPackage, callingFeatureId); } catch (SecurityException e) { return false; } @@ -203,7 +216,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Connection state of default APN type data (i.e. internet) of phones private int[] mDataConnectionState; - private Bundle[] mCellLocation; + private CellIdentity[] mCellIdentity; private int[] mDataConnectionNetworkType; @@ -226,7 +239,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX; + private int mDefaultPhoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; private int[] mRingingCallState; @@ -269,11 +282,15 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { static final int ENFORCE_PHONE_STATE_PERMISSION_MASK = PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR - | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST; + | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST + | PhoneStateListener.LISTEN_REGISTRATION_FAILURE; static final int PRECISE_PHONE_STATE_PERMISSION_MASK = - PhoneStateListener.LISTEN_PRECISE_CALL_STATE | - PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE; + PhoneStateListener.LISTEN_PRECISE_CALL_STATE + | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE + | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES + | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED + | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES; static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK = PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL @@ -291,7 +308,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { int numPhones = getTelephonyManager().getPhoneCount(); for (int sub = 0; sub < numPhones; sub++) { TelephonyRegistry.this.notifyCellLocationForSubscriber(sub, - mCellLocation[sub]); + mCellIdentity[sub]); } break; } @@ -355,7 +372,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { SubscriptionManager.getDefaultSubscriptionId()); int newDefaultPhoneId = intent.getIntExtra( SubscriptionManager.EXTRA_SLOT_INDEX, - SubscriptionManager.getPhoneId(newDefaultSubId)); + getPhoneIdFromSubId(newDefaultSubId)); if (DBG) { log("onReceive:current mDefaultSubId=" + mDefaultSubId + " current mDefaultPhoneId=" + mDefaultPhoneId @@ -397,10 +414,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mVoiceActivationState = copyOf(mVoiceActivationState, mNumPhones); mDataActivationState = copyOf(mDataActivationState, mNumPhones); mUserMobileDataState = copyOf(mUserMobileDataState, mNumPhones); - mSignalStrength = copyOf(mSignalStrength, mNumPhones); + if (mSignalStrength != null) { + mSignalStrength = copyOf(mSignalStrength, mNumPhones); + } else { + mSignalStrength = new SignalStrength[mNumPhones]; + } mMessageWaiting = copyOf(mMessageWaiting, mNumPhones); mCallForwarding = copyOf(mCallForwarding, mNumPhones); - mCellLocation = copyOf(mCellLocation, mNumPhones); + mCellIdentity = copyOf(mCellIdentity, mNumPhones); mSrvccState = copyOf(mSrvccState, mNumPhones); mPreciseCallState = copyOf(mPreciseCallState, mNumPhones); mForegroundCallState = copyOf(mForegroundCallState, mNumPhones); @@ -431,11 +452,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN; mCallIncomingNumber[i] = ""; mServiceState[i] = new ServiceState(); - mSignalStrength[i] = new SignalStrength(); + mSignalStrength[i] = null; mUserMobileDataState[i] = false; mMessageWaiting[i] = false; mCallForwarding[i] = false; - mCellLocation[i] = new Bundle(); + mCellIdentity[i] = null; mCellInfo.add(i, null); mImsReasonInfo.add(i, null); mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE; @@ -451,15 +472,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE; mPreciseDataConnectionStates.add(new HashMap<String, PreciseDataConnectionState>()); } - - // Note that location can be null for non-phone builds like - // like the generic one. - CellLocation location = CellLocation.getEmpty(); - if (location != null) { - for (int i = oldNumPhones; i < mNumPhones; i++) { - location.fillInNotifierBundle(mCellLocation[i]); - } - } } private void cutListToSize(List list, int size) { @@ -499,7 +511,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mSignalStrength = new SignalStrength[numPhones]; mMessageWaiting = new boolean[numPhones]; mCallForwarding = new boolean[numPhones]; - mCellLocation = new Bundle[numPhones]; + mCellIdentity = new CellIdentity[numPhones]; mSrvccState = new int[numPhones]; mPreciseCallState = new PreciseCallState[numPhones]; mForegroundCallState = new int[numPhones]; @@ -524,11 +536,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN; mCallIncomingNumber[i] = ""; mServiceState[i] = new ServiceState(); - mSignalStrength[i] = new SignalStrength(); + mSignalStrength[i] = null; mUserMobileDataState[i] = false; mMessageWaiting[i] = false; mCallForwarding[i] = false; - mCellLocation[i] = new Bundle(); + mCellIdentity[i] = null; mCellInfo.add(i, null); mImsReasonInfo.add(i, null); mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE; @@ -545,14 +557,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPreciseDataConnectionStates.add(new HashMap<String, PreciseDataConnectionState>()); } - // Note that location can be null for non-phone builds like - // like the generic one. - if (location != null) { - for (int i = 0; i < numPhones; i++) { - location.fillInNotifierBundle(mCellLocation[i]); - } - } - mAppOps = mContext.getSystemService(AppOpsManager.class); } @@ -568,7 +572,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override - public void addOnSubscriptionsChangedListener(String callingPackage, + public void addOnSubscriptionsChangedListener(String callingPackage, String callingFeatureId, IOnSubscriptionsChangedListener callback) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); @@ -590,6 +594,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.context = mContext; r.onSubscriptionsChangedListenerCallback = callback; r.callingPackage = callingPackage; + r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); r.events = 0; @@ -622,7 +627,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { @Override public void addOnOpportunisticSubscriptionsChangedListener(String callingPackage, - IOnSubscriptionsChangedListener callback) { + String callingFeatureId, IOnSubscriptionsChangedListener callback) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); if (VDBG) { @@ -643,6 +648,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.context = mContext; r.onOpportunisticSubscriptionsChangedListenerCallback = callback; r.callingPackage = callingPackage; + r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); r.events = 0; @@ -718,21 +724,28 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + @Deprecated @Override - public void listen(String pkgForDebug, IPhoneStateListener callback, int events, + public void listen(String callingPackage, IPhoneStateListener callback, int events, boolean notifyNow) { - listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, pkgForDebug, callback, - events, notifyNow); + listenWithFeature(callingPackage, null, callback, events, notifyNow); } @Override - public void listenForSubscriber(int subId, String pkgForDebug, IPhoneStateListener callback, - int events, boolean notifyNow) { - listen(pkgForDebug, callback, events, notifyNow, subId); + public void listenWithFeature(String callingPackage, String callingFeatureId, + IPhoneStateListener callback, int events, boolean notifyNow) { + listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, callingPackage, + callingFeatureId, callback, events, notifyNow); } - private void listen(String callingPackage, IPhoneStateListener callback, int events, - boolean notifyNow, int subId) { + @Override + public void listenForSubscriber(int subId, String callingPackage, String callingFeatureId, + IPhoneStateListener callback, int events, boolean notifyNow) { + listen(callingPackage, callingFeatureId, callback, events, notifyNow, subId); + } + + private void listen(String callingPackage, @Nullable String callingFeatureId, + IPhoneStateListener callback, int events, boolean notifyNow, int subId) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); String str = "listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events) @@ -747,11 +760,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Checks permission and throws SecurityException for disallowed operations. For pre-M // apps whose runtime permission has been revoked, we return immediately to skip sending // events to the app without crashing it. - if (!checkListenerPermission(events, subId, callingPackage, "listen")) { + if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId, + "listen")) { return; } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { // register IBinder b = callback.asBinder(); @@ -764,6 +778,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.context = mContext; r.callback = callback; r.callingPackage = callingPackage; + r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, @@ -786,9 +801,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onServiceStateChanged(rawSs); } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(false)); + r.callback.onServiceStateChanged( + rawSs.createLocationInfoSanitizedCopy(false)); } else { - r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(true)); + r.callback.onServiceStateChanged( + rawSs.createLocationInfoSanitizedCopy(true)); } } catch (RemoteException ex) { remove(r.binder); @@ -796,10 +813,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { try { - int gsmSignalStrength = mSignalStrength[phoneId] - .getGsmSignalStrength(); - r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 - : gsmSignalStrength)); + if (mSignalStrength[phoneId] != null) { + int gsmSignalStrength = mSignalStrength[phoneId] + .getGsmSignalStrength(); + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); + } } catch (RemoteException ex) { remove(r.binder); } @@ -822,11 +841,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { try { - if (DBG_LOC) log("listen: mCellLocation = " - + mCellLocation[phoneId]); + if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]); if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onCellLocationChanged( - new Bundle(mCellLocation[phoneId])); + // null will be translated to empty CellLocation object in client. + r.callback.onCellLocationChanged(mCellIdentity[phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -857,7 +875,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { try { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); + if (mSignalStrength[phoneId] != null) { + r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); + } } catch (RemoteException ex) { remove(r.binder); } @@ -1077,7 +1097,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Called only by Telecomm to communicate call state across different phone accounts. So // there is no need to add a valid subId or slotId. broadcastCallStateChanged(state, phoneNumber, - SubscriptionManager.INVALID_PHONE_INDEX, + SubscriptionManager.INVALID_SIM_SLOT_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); } @@ -1144,9 +1164,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { stateToSend = new ServiceState(state); } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { - stateToSend = state.sanitizeLocationInfo(false); + stateToSend = state.createLocationInfoSanitizedCopy(false); } else { - stateToSend = state.sanitizeLocationInfo(true); + stateToSend = state.createLocationInfoSanitizedCopy(true); } if (DBG) { log("notifyServiceStateForSubscriber: callback.onSSC r=" + r @@ -1291,7 +1311,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // only CarrierService with carrier privilege rule should have the permission int[] subIds = Arrays.stream(SubscriptionManager.from(mContext) .getActiveSubscriptionIdList(false)) - .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray(); + .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext, + i)).toArray(); if (ArrayUtils.isEmpty(subIds)) { loge("notifyCarrierNetworkChange without carrier privilege"); // the active subId does not have carrier privilege. @@ -1301,7 +1322,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { mCarrierNetworkChangeState = active; for (int subId : subIds) { - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); if (VDBG) { log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId); @@ -1334,7 +1355,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCellInfoForSubscriber: subId=" + subId + " cellInfo=" + cellInfo); } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mCellInfo.set(phoneId, cellInfo); @@ -1425,7 +1446,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCallForwardingChangedForSubscriber: subId=" + subId + " cfi=" + cfi); } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mCallForwarding[phoneId] = cfi; @@ -1453,7 +1474,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifyDataActivity()" )) { return; } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mDataActivity[phoneId] = state; @@ -1593,7 +1614,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN, ApnSetting.getApnTypesBitmaskFromString(apnType), null, null, - DataFailCause.NONE)); + DataFailCause.NONE, null)); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) @@ -1610,14 +1631,15 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { handleRemoveListLocked(); } - broadcastDataConnectionFailed(apnType, subId); } - public void notifyCellLocation(Bundle cellLocation) { - notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellLocation); + @Override + public void notifyCellLocation(CellIdentity cellLocation) { + notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellLocation); } - public void notifyCellLocationForSubscriber(int subId, Bundle cellLocation) { + @Override + public void notifyCellLocationForSubscriber(int subId, CellIdentity cellLocation) { log("notifyCellLocationForSubscriber: subId=" + subId + " cellLocation=" + cellLocation); if (!checkNotifyPermission("notifyCellLocation()")) { @@ -1627,10 +1649,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCellLocationForSubscriber: subId=" + subId + " cellLocation=" + cellLocation); } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { - mCellLocation[phoneId] = cellLocation; + mCellIdentity[phoneId] = cellLocation; for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) && idMatch(r.subId, subId, phoneId) && @@ -1640,7 +1662,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCellLocation: cellLocation=" + cellLocation + " r=" + r); } - r.callback.onCellLocationChanged(new Bundle(cellLocation)); + r.callback.onCellLocationChanged(cellLocation); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -1736,7 +1758,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifyImsCallDisconnectCause()")) { return; } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mImsReasonInfo.set(phoneId, imsReasonInfo); @@ -1777,7 +1799,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN, ApnSetting.getApnTypesBitmaskFromString(apnType), null, null, - failCause)); + failCause, null)); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) @@ -1803,7 +1825,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (VDBG) { log("notifySrvccStateChanged: subId=" + subId + " srvccState=" + state); } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mSrvccState[phoneId] = state; @@ -2049,6 +2071,40 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override + public void notifyRegistrationFailed(int phoneId, int subId, @NonNull CellIdentity cellIdentity, + @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) { + if (!checkNotifyPermission("notifyRegistrationFailed()")) { + return; + } + + // In case callers don't have fine location access, pre-construct a location-free version + // of the CellIdentity. This will still have the PLMN ID, which should be sufficient for + // most purposes. + final CellIdentity noLocationCi = cellIdentity.sanitizeLocationInfo(); + + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.LISTEN_REGISTRATION_FAILURE) + && idMatch(r.subId, subId, phoneId)) { + try { + r.callback.onRegistrationFailed( + checkFineLocationAccess(r, Build.VERSION_CODES.R) + ? cellIdentity : noLocationCi, + chosenPlmn, domain, causeCode, + additionalCauseCode); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); @@ -2077,7 +2133,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mCallForwarding=" + mCallForwarding[i]); pw.println("mDataActivity=" + mDataActivity[i]); pw.println("mDataConnectionState=" + mDataConnectionState[i]); - pw.println("mCellLocation=" + mCellLocation[i]); + pw.println("mCellIdentity=" + mCellIdentity[i]); pw.println("mCellInfo=" + mCellInfo.get(i)); pw.println("mImsCallDisconnectCause=" + mImsReasonInfo.get(i)); pw.println("mSrvccState=" + mSrvccState[i]); @@ -2166,13 +2222,32 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED); Bundle data = new Bundle(); - signalStrength.fillInNotifierBundle(data); + fillInSignalStrengthNotifierBundle(signalStrength, data); intent.putExtras(data); intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } + private void fillInSignalStrengthNotifierBundle(SignalStrength signalStrength, Bundle bundle) { + List<CellSignalStrength> cellSignalStrengths = signalStrength.getCellSignalStrengths(); + for (CellSignalStrength cellSignalStrength : cellSignalStrengths) { + if (cellSignalStrength instanceof CellSignalStrengthLte) { + bundle.putParcelable("Lte", (CellSignalStrengthLte) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthCdma) { + bundle.putParcelable("Cdma", (CellSignalStrengthCdma) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthGsm) { + bundle.putParcelable("Gsm", (CellSignalStrengthGsm) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthWcdma) { + bundle.putParcelable("Wcdma", (CellSignalStrengthWcdma) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthTdscdma) { + bundle.putParcelable("Tdscdma", (CellSignalStrengthTdscdma) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthNr) { + bundle.putParcelable("Nr", (CellSignalStrengthNr) cellSignalStrength); + } + } + } + /** * Broadcasts an intent notifying apps of a phone state change. {@code subId} can be * a valid subId, in which case this function fires a subId-specific intent, or it @@ -2209,7 +2284,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); } // If the phoneId is invalid, the broadcast is for overall call state. - if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) { + if (phoneId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); } @@ -2259,19 +2334,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private void broadcastDataConnectionFailed(String apnType, int subId) { - Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); - intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType); - intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - private void enforceNotifyPermissionOrCarrierPrivilege(String method) { if (checkNotifyPermission()) { return; } - TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege( + TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, SubscriptionManager.getDefaultSubscriptionId(), method); } @@ -2290,8 +2358,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { == PackageManager.PERMISSION_GRANTED; } - private boolean checkListenerPermission( - int events, int subId, String callingPackage, String message) { + private boolean checkListenerPermission(int events, int subId, String callingPackage, + @Nullable String callingFeatureId, String message) { LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder = new LocationAccessPolicy.LocationPermissionQuery.Builder() .setCallingPackage(callingPackage) @@ -2326,14 +2394,20 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( - mContext, subId, callingPackage, message)) { + mContext, subId, callingPackage, callingFeatureId, message)) { return false; } } if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); + // check if calling app has either permission READ_PRECISE_PHONE_STATE + // or with carrier privileges + try { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); + } catch (SecurityException se) { + TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, subId, message); + } } if ((events & READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK) != 0) { @@ -2351,16 +2425,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); } - if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); - } - - if ((events & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); - } - if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); @@ -2371,11 +2435,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); } - if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); - } - return true; } @@ -2488,11 +2547,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { try { - SignalStrength signalStrength = mSignalStrength[phoneId]; - if (DBG) { - log("checkPossibleMissNotify: onSignalStrengthsChanged SS=" + signalStrength); + if (mSignalStrength[phoneId] != null) { + SignalStrength signalStrength = mSignalStrength[phoneId]; + if (DBG) { + log("checkPossibleMissNotify: onSignalStrengthsChanged SS=" + + signalStrength); + } + r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); } - r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2500,14 +2562,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { try { - int gsmSignalStrength = mSignalStrength[phoneId] - .getGsmSignalStrength(); - if (DBG) { - log("checkPossibleMissNotify: onSignalStrengthChanged SS=" + - gsmSignalStrength); + if (mSignalStrength[phoneId] != null) { + int gsmSignalStrength = mSignalStrength[phoneId] + .getGsmSignalStrength(); + if (DBG) { + log("checkPossibleMissNotify: onSignalStrengthChanged SS=" + + gsmSignalStrength); + } + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); } - r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 - : gsmSignalStrength)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2567,10 +2631,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { try { - if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = " - + mCellLocation[phoneId]); + if (DBG_LOC) { + log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = " + + mCellIdentity[phoneId]); + } if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId])); + // null will be translated to empty CellLocation object in client. + r.callback.onCellLocationChanged(mCellIdentity[phoneId]); } } catch (RemoteException ex) { mRemoveList.add(r.binder); @@ -2653,8 +2720,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return "TD_SCDMA"; case TelephonyManager.NETWORK_TYPE_IWLAN: return "IWLAN"; - case TelephonyManager.NETWORK_TYPE_LTE_CA: - return "LTE_CA"; + + //TODO: This network type is marked as hidden because it is not a + // true network type and we are looking to remove it completely from the available list + // of network types. Since this method is only used for logging, in the event that this + // network type is selected, the log will read as "Unknown." + //case TelephonyManager.NETWORK_TYPE_LTE_CA: + // return "LTE_CA"; + case TelephonyManager.NETWORK_TYPE_NR: return "NR"; default: @@ -2675,4 +2748,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private static CallQuality createCallQuality() { return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } + + private int getPhoneIdFromSubId(int subId) { + SubscriptionManager subManager = (SubscriptionManager) + mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + if (subManager == null) return INVALID_SIM_SLOT_INDEX; + + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + subId = SubscriptionManager.getDefaultSubscriptionId(); + } + + SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId); + if (info == null) return INVALID_SIM_SLOT_INDEX; + return info.getSimSlotIndex(); + } } diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index d19d2ddd7c3c..a7e36b23a98b 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -219,7 +219,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { // Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up // resources, even for binder death or unwanted calls. synchronized (mTestNetworkTracker) { - mTestNetworkTracker.remove(netId); + mTestNetworkTracker.remove(network.netId); } } } @@ -338,7 +338,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { callingUid, binder); - mTestNetworkTracker.put(agent.netId, agent); + mTestNetworkTracker.put(agent.network.netId, agent); } } catch (SocketException e) { throw new UncheckedIOException(e); diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index a1480e305d9e..e7179e09c4b3 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -60,7 +60,6 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.DebugUtils; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.StatsLog; @@ -162,8 +161,7 @@ public class VibratorService extends IVibratorService.Stub private int mHapticFeedbackIntensity; private int mNotificationIntensity; private int mRingIntensity; - private SparseArray<Pair<VibrationEffect, AudioAttributes>> mAlwaysOnEffects = - new SparseArray<>(); + private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>(); static native boolean vibratorExists(); static native void vibratorInit(); @@ -477,6 +475,10 @@ public class VibratorService extends IVibratorService.Stub Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY), true, mSettingObserver, UserHandle.USER_ALL); + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ZEN_MODE), + true, mSettingObserver, UserHandle.USER_ALL); + mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -524,7 +526,8 @@ public class VibratorService extends IVibratorService.Stub } @Override // Binder call - public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attrs) { + public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, + AudioAttributes attrs) { if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) { throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission"); } @@ -534,8 +537,8 @@ public class VibratorService extends IVibratorService.Stub } if (effect == null) { synchronized (mLock) { - mAlwaysOnEffects.delete(id); - vibratorAlwaysOnDisable(id); + mAlwaysOnEffects.delete(alwaysOnId); + vibratorAlwaysOnDisable(alwaysOnId); } } else { if (!verifyVibrationEffect(effect)) { @@ -545,14 +548,11 @@ public class VibratorService extends IVibratorService.Stub Slog.e(TAG, "Only prebaked effects supported for always-on."); return false; } - if (attrs == null) { - attrs = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_UNKNOWN) - .build(); - } + attrs = fixupVibrationAttributes(attrs); synchronized (mLock) { - mAlwaysOnEffects.put(id, Pair.create(effect, attrs)); - updateAlwaysOnLocked(id, effect, attrs); + Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null); + mAlwaysOnEffects.put(alwaysOnId, vib); + updateAlwaysOnLocked(alwaysOnId, vib); } } return true; @@ -592,6 +592,25 @@ public class VibratorService extends IVibratorService.Stub return true; } + private AudioAttributes fixupVibrationAttributes(AudioAttributes attrs) { + if (attrs == null) { + attrs = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_UNKNOWN) + .build(); + } + if (shouldBypassDnd(attrs)) { + if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) { + final int flags = attrs.getAllFlags() + & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; + attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build(); + } + } + + return attrs; + } + private static long[] getLongIntArray(Resources r, int resid) { int[] ar = r.getIntArray(resid); if (ar == null) { @@ -621,21 +640,7 @@ public class VibratorService extends IVibratorService.Stub return; } - if (attrs == null) { - attrs = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_UNKNOWN) - .build(); - } - - if (shouldBypassDnd(attrs)) { - if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) - || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) { - final int flags = attrs.getAllFlags() - & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; - attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build(); - } - } + attrs = fixupVibrationAttributes(attrs); // If our current vibration is longer than the new vibration and is the same amplitude, // then just let the current one finish. @@ -796,29 +801,8 @@ public class VibratorService extends IVibratorService.Stub private void startVibrationLocked(final Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked"); try { - if (!isAllowedToVibrateLocked(vib)) { - return; - } - final int intensity = getCurrentIntensityLocked(vib); - if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { - return; - } - - if (vib.isRingtone() && !shouldVibrateForRingtone()) { - if (DEBUG) { - Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); - } - return; - } - - final int mode = getAppOpMode(vib); - if (mode != AppOpsManager.MODE_ALLOWED) { - if (mode == AppOpsManager.MODE_ERRORED) { - // We might be getting calls from within system_server, so we don't actually - // want to throw a SecurityException here. - Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); - } + if (!shouldVibrate(vib, intensity)) { return; } applyVibrationIntensityScalingLocked(vib, intensity); @@ -985,6 +969,35 @@ public class VibratorService extends IVibratorService.Stub return mode; } + private boolean shouldVibrate(Vibration vib, int intensity) { + if (!isAllowedToVibrateLocked(vib)) { + return false; + } + + if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { + return false; + } + + if (vib.isRingtone() && !shouldVibrateForRingtone()) { + if (DEBUG) { + Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); + } + return false; + } + + final int mode = getAppOpMode(vib); + if (mode != AppOpsManager.MODE_ALLOWED) { + if (mode == AppOpsManager.MODE_ERRORED) { + // We might be getting calls from within system_server, so we don't actually + // want to throw a SecurityException here. + Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); + } + return false; + } + + return true; + } + @GuardedBy("mLock") private void reportFinishVibrationLocked() { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); @@ -1096,14 +1109,12 @@ public class VibratorService extends IVibratorService.Stub mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT); } - private void updateAlwaysOnLocked(int id, VibrationEffect effect, AudioAttributes attrs) { - // TODO: Check DND and LowPower settings - final Vibration vib = new Vibration(null, effect, attrs, 0, null, null); + private void updateAlwaysOnLocked(int id, Vibration vib) { final int intensity = getCurrentIntensityLocked(vib); - if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { + if (!shouldVibrate(vib, intensity)) { vibratorAlwaysOnDisable(id); } else { - final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; + final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; final int strength = intensityToEffectStrength(intensity); vibratorAlwaysOnEnable(id, prebaked.getId(), strength); } @@ -1112,8 +1123,8 @@ public class VibratorService extends IVibratorService.Stub private void updateAlwaysOnLocked() { for (int i = 0; i < mAlwaysOnEffects.size(); i++) { int id = mAlwaysOnEffects.keyAt(i); - Pair<VibrationEffect, AudioAttributes> pair = mAlwaysOnEffects.valueAt(i); - updateAlwaysOnLocked(id, pair.first, pair.second); + Vibration vib = mAlwaysOnEffects.valueAt(i); + updateAlwaysOnLocked(id, vib); } } diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java index 7fd98e0043c9..c125b1baf860 100644 --- a/services/core/java/com/android/server/adb/AdbService.java +++ b/services/core/java/com/android/server/adb/AdbService.java @@ -17,6 +17,7 @@ package com.android.server.adb; import android.content.ContentResolver; import android.content.Context; +import android.content.pm.PackageManager; import android.database.ContentObserver; import android.debug.AdbManagerInternal; import android.debug.IAdbManager; @@ -260,6 +261,30 @@ public class AdbService extends IAdbManager.Stub { } } + /** + * @return true if the device supports secure ADB over Wi-Fi. + * @hide + */ + @Override + public boolean isAdbWifiSupported() { + mContext.enforceCallingPermission( + android.Manifest.permission.MANAGE_DEBUGGING, "AdbService"); + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI); + } + + /** + * @return true if the device supports secure ADB over Wi-Fi and device pairing by + * QR code. + * @hide + */ + @Override + public boolean isAdbWifiQrSupported() { + mContext.enforceCallingPermission( + android.Manifest.permission.MANAGE_DEBUGGING, "AdbService"); + return isAdbWifiSupported() && mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_CAMERA_ANY); + } + private void setAdbEnabled(boolean enable) { if (DEBUG) Slog.d(TAG, "setAdbEnabled(" + enable + "), mAdbEnabled=" + mAdbEnabled); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1c4f1e3ed5bf..2af04ae3f800 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5280,7 +5280,7 @@ public class ActivityManagerService extends IActivityManager.Stub storageManager.commitChanges(); } catch (Exception e) { PowerManager pm = (PowerManager) - mInjector.getContext().getSystemService(Context.POWER_SERVICE); + mContext.getSystemService(Context.POWER_SERVICE); pm.reboot("Checkpoint commit failed"); } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index b406ce6c3ca8..972b10608056 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2899,33 +2899,37 @@ final class ActivityManagerShellCommand extends ShellCommand { } ArraySet<Long> enabled = new ArraySet<>(); ArraySet<Long> disabled = new ArraySet<>(); - switch (toggleValue) { - case "enable": - enabled.add(changeId); - pw.println("Enabled change " + changeId + " for " + packageName + "."); - CompatibilityChangeConfig overrides = - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)); - platformCompat.setOverrides(overrides, packageName); - return 0; - case "disable": - disabled.add(changeId); - pw.println("Disabled change " + changeId + " for " + packageName + "."); - overrides = - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)); - platformCompat.setOverrides(overrides, packageName); - return 0; - case "reset": - if (platformCompat.clearOverride(changeId, packageName)) { - pw.println("Reset change " + changeId + " for " + packageName - + " to default value."); - } else { - pw.println("No override exists for changeId " + changeId + "."); - } - return 0; - default: - pw.println("Invalid toggle value: '" + toggleValue + "'."); + try { + switch (toggleValue) { + case "enable": + enabled.add(changeId); + CompatibilityChangeConfig overrides = + new CompatibilityChangeConfig( + new Compatibility.ChangeConfig(enabled, disabled)); + platformCompat.setOverrides(overrides, packageName); + pw.println("Enabled change " + changeId + " for " + packageName + "."); + return 0; + case "disable": + disabled.add(changeId); + overrides = + new CompatibilityChangeConfig( + new Compatibility.ChangeConfig(enabled, disabled)); + platformCompat.setOverrides(overrides, packageName); + pw.println("Disabled change " + changeId + " for " + packageName + "."); + return 0; + case "reset": + if (platformCompat.clearOverride(changeId, packageName)) { + pw.println("Reset change " + changeId + " for " + packageName + + " to default value."); + } else { + pw.println("No override exists for changeId " + changeId + "."); + } + return 0; + default: + pw.println("Invalid toggle value: '" + toggleValue + "'."); + } + } catch (SecurityException e) { + pw.println(e.getMessage()); } return -1; } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index f5579761c151..c2652c06e5a9 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityThread.PROC_START_SEQ_IDENT; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static android.os.Process.getFreeMemory; @@ -57,6 +58,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.Resources; import android.graphics.Point; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; import android.os.AppZygote; import android.os.Binder; import android.os.Build; @@ -74,6 +77,7 @@ import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; +import android.system.Os; import android.text.TextUtils; import android.util.ArrayMap; import android.util.EventLog; @@ -102,6 +106,7 @@ import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; @@ -245,6 +250,10 @@ public final class ProcessList { private static final String PROPERTY_USE_APP_IMAGE_STARTUP_CACHE = "persist.device_config.runtime_native.use_app_image_startup_cache"; + // The socket path for zygote to send unsolicited msg. + // Must keep sync with com_android_internal_os_Zygote.cpp. + private static final String UNSOL_ZYGOTE_MSG_SOCKET_PATH = "/data/system/unsolzygotesocket"; + // Low Memory Killer Daemon command codes. // These must be kept in sync with lmk_cmd definitions in lmkd.h // @@ -388,6 +397,28 @@ public final class ProcessList { private PlatformCompat mPlatformCompat = null; + /** + * The server socket in system_server, zygote will connect to it + * in order to send unsolicited messages to system_server. + */ + private LocalSocket mSystemServerSocketForZygote; + + /** + * Maximum number of bytes that an incoming unsolicited zygote message could be. + * To be updated if new message type needs to be supported. + */ + private static final int MAX_ZYGOTE_UNSOLICITED_MESSAGE_SIZE = 16; + + /** + * The buffer to be used to receive the incoming unsolicited zygote message. + */ + private final byte[] mZygoteUnsolicitedMessage = new byte[MAX_ZYGOTE_UNSOLICITED_MESSAGE_SIZE]; + + /** + * The buffer to be used to receive the SIGCHLD data, it includes pid/uid/status. + */ + private final int[] mZygoteSigChldMessage = new int[3]; + interface LmkdKillListener { /** * Called when there is a process kill by lmkd. @@ -645,6 +676,13 @@ public final class ProcessList { } } ); + // Start listening on incoming connections from zygotes. + mSystemServerSocketForZygote = createSystemServerSocketForZygote(); + if (mSystemServerSocketForZygote != null) { + sKillHandler.getLooper().getQueue().addOnFileDescriptorEventListener( + mSystemServerSocketForZygote.getFileDescriptor(), + EVENT_INPUT, this::handleZygoteMessages); + } } } @@ -1363,7 +1401,7 @@ public final class ProcessList { final int procCount = procs.size(); for (int i = 0; i < procCount; i++) { final int procUid = procs.keyAt(i); - if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) { + if (!UserHandle.isCore(procUid) || !UserHandle.isSameUser(procUid, uid)) { // Don't use an app process or different user process for system component. continue; } @@ -3267,4 +3305,66 @@ public final class ProcessList { } } } + + private void handleZygoteSigChld(int pid, int uid, int status) { + // Just log it now. + if (DEBUG_PROCESSES) { + Slog.i(TAG, "Got SIGCHLD from zygote: pid=" + pid + ", uid=" + uid + + ", status=" + Integer.toHexString(status)); + } + } + + /** + * Create a server socket in system_server, zygote will connect to it + * in order to send unsolicited messages to system_server. + */ + private LocalSocket createSystemServerSocketForZygote() { + // The file system entity for this socket is created with 0666 perms, owned + // by system:system. selinux restricts things so that only zygotes can + // access it. + final File socketFile = new File(UNSOL_ZYGOTE_MSG_SOCKET_PATH); + if (socketFile.exists()) { + socketFile.delete(); + } + + LocalSocket serverSocket = null; + try { + serverSocket = new LocalSocket(LocalSocket.SOCKET_DGRAM); + serverSocket.bind(new LocalSocketAddress( + UNSOL_ZYGOTE_MSG_SOCKET_PATH, LocalSocketAddress.Namespace.FILESYSTEM)); + Os.chmod(UNSOL_ZYGOTE_MSG_SOCKET_PATH, 0666); + } catch (Exception e) { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException ex) { + } + serverSocket = null; + } + } + return serverSocket; + } + + /** + * Handle the unsolicited message from zygote. + */ + private int handleZygoteMessages(FileDescriptor fd, int events) { + final int eventFd = fd.getInt$(); + if ((events & EVENT_INPUT) != 0) { + // An incoming message from zygote + try { + final int len = Os.read(fd, mZygoteUnsolicitedMessage, 0, + mZygoteUnsolicitedMessage.length); + if (len > 0 && mZygoteSigChldMessage.length == Zygote.nativeParseSigChld( + mZygoteUnsolicitedMessage, len, mZygoteSigChldMessage)) { + handleZygoteSigChld(mZygoteSigChldMessage[0] /* pid */, + mZygoteSigChldMessage[1] /* uid */, + mZygoteSigChldMessage[2] /* status */); + } + } catch (Exception e) { + Slog.w(TAG, "Exception in reading unsolicited zygote message: " + e); + } + } + return EVENT_INPUT; + } } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 314e04c8da32..d45bc72aee11 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1110,8 +1110,8 @@ public class AppOpsService extends IAppOpsService.Stub { return Collections.emptyList(); } synchronized (this) { - Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */, - false /* uidMismatchExpected */); + Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */, + false /* edit */); if (pkgOps == null) { return null; } @@ -1208,8 +1208,7 @@ public class AppOpsService extends IAppOpsService.Stub { private void pruneOp(Op op, int uid, String packageName) { if (!op.hasAnyTime()) { - Ops ops = getOpsRawLocked(uid, packageName, false /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */, false /* edit */); if (ops != null) { ops.remove(op.op); if (ops.size() <= 0) { @@ -1409,11 +1408,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } - @Override - public void setMode(int code, int uid, String packageName, int mode) { - setMode(code, uid, packageName, mode, true, false); - } - /** * Sets the mode for a certain op and uid. * @@ -1421,19 +1415,25 @@ public class AppOpsService extends IAppOpsService.Stub { * @param uid The UID for which to set * @param packageName The package for which to set * @param mode The new mode to set - * @param verifyUid Iff {@code true}, check that the package name belongs to the uid - * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid == - * false}) */ - private void setMode(int code, int uid, @NonNull String packageName, int mode, - boolean verifyUid, boolean isPrivileged) { + @Override + public void setMode(int code, int uid, @NonNull String packageName, int mode) { enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); verifyIncomingOp(code); ArraySet<ModeCallback> repCbs = null; code = AppOpsManager.opToSwitch(code); + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot setMode", e); + return; + } + synchronized (this) { UidState uidState = getUidStateLocked(uid, false); - Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged); + Op op = getOpLocked(code, uid, packageName, isPrivileged, true); if (op != null) { if (op.mode != mode) { op.mode = mode; @@ -1799,34 +1799,32 @@ public class AppOpsService extends IAppOpsService.Stub { } /** - * @see #checkOperationUnchecked(int, int, String, boolean, boolean) - */ - private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, - boolean raw) { - return checkOperationUnchecked(code, uid, packageName, raw, true); - } - - /** * Get the mode of an app-op. * * @param code The code of the op * @param uid The uid of the package the op belongs to * @param packageName The package the op belongs to * @param raw If the raw state of eval-ed state should be checked. - * @param verify If the code should check the package belongs to the uid * * @return The mode of the op */ private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, - boolean raw, boolean verify) { + boolean raw) { if (isOpRestrictedDueToSuspend(code, packageName, uid)) { return AppOpsManager.MODE_IGNORED; } + + boolean isPrivileged; + + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "checkOperation", e); + return AppOpsManager.opToDefaultMode(code); + } + synchronized (this) { - if (verify) { - checkPackage(uid, packageName); - } - if (isOpRestrictedLocked(uid, code, packageName)) { + if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } code = AppOpsManager.opToSwitch(code); @@ -1836,7 +1834,7 @@ public class AppOpsService extends IAppOpsService.Stub { final int rawMode = uidState.opModes.get(code); return raw ? rawMode : uidState.evalMode(code, rawMode); } - Op op = getOpLocked(code, uid, packageName, false, verify, false); + Op op = getOpLocked(code, uid, packageName, false, false); if (op == null) { return AppOpsManager.opToDefaultMode(code); } @@ -1941,14 +1939,12 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public int checkPackage(int uid, String packageName) { Preconditions.checkNotNull(packageName); - synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - true /* uidMismatchExpected */); - if (ops != null) { - return AppOpsManager.MODE_ALLOWED; - } else { - return AppOpsManager.MODE_ERRORED; - } + try { + verifyAndGetIsPrivileged(uid, packageName); + + return AppOpsManager.MODE_ALLOWED; + } catch (SecurityException ignored) { + return AppOpsManager.MODE_ERRORED; } } @@ -2011,9 +2007,16 @@ public class AppOpsService extends IAppOpsService.Stub { private int noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName, @OpFlags int flags) { + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "noteOperation", e); + return AppOpsManager.MODE_ERRORED; + } + synchronized (this) { - final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */); if (ops == null) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); @@ -2022,7 +2025,7 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); - if (isOpRestrictedLocked(uid, code, packageName)) { + if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); return AppOpsManager.MODE_IGNORED; @@ -2181,16 +2184,25 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_IGNORED; } ClientState client = (ClientState)token; + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "startOperation", e); + return AppOpsManager.MODE_ERRORED; + } + synchronized (this) { - final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */, - false /* uidMismatchExpected */); + final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged, + true /* edit */); if (ops == null) { if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid + " package " + resolvedPackageName); return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); - if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { + if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } final int switchCode = AppOpsManager.opToSwitch(code); @@ -2262,8 +2274,17 @@ public class AppOpsService extends IAppOpsService.Stub { return; } ClientState client = (ClientState) token; + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot finishOperation", e); + return; + } + synchronized (this) { - Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false); + Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true); if (op == null) { return; } @@ -2513,8 +2534,76 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.pendingStateCommitTime = 0; } - private Ops getOpsRawLocked(int uid, String packageName, boolean edit, - boolean uidMismatchExpected) { + /** + * Verify that package belongs to uid and return whether the package is privileged. + * + * @param uid The uid the package belongs to + * @param packageName The package the might belong to the uid + * + * @return {@code true} iff the package is privileged + */ + private boolean verifyAndGetIsPrivileged(int uid, String packageName) { + if (uid == Process.ROOT_UID) { + // For backwards compatibility, don't check package name for root UID. + return false; + } + + // Do not check if uid/packageName is already known + synchronized (this) { + UidState uidState = mUidStates.get(uid); + if (uidState != null && uidState.pkgOps != null) { + Ops ops = uidState.pkgOps.get(packageName); + + if (ops != null) { + return ops.isPrivileged; + } + } + } + + boolean isPrivileged = false; + final long ident = Binder.clearCallingIdentity(); + try { + int pkgUid; + + ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class) + .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_INSTANT, + Process.SYSTEM_UID, UserHandle.getUserId(uid)); + if (appInfo != null) { + pkgUid = appInfo.uid; + isPrivileged = (appInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + } else { + pkgUid = resolveUid(packageName); + if (pkgUid >= 0) { + isPrivileged = false; + } + } + if (pkgUid != uid) { + throw new SecurityException("Specified package " + packageName + " under uid " + uid + + " but it is really " + pkgUid); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + + return isPrivileged; + } + + /** + * Get (and potentially create) ops. + * + * @param uid The uid the package belongs to + * @param packageName The name of the package + * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false) + * @param edit If an ops does not exist, create the ops? + + * @return + */ + private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) { UidState uidState = getUidStateLocked(uid, edit); if (uidState == null) { return null; @@ -2532,47 +2621,6 @@ public class AppOpsService extends IAppOpsService.Stub { if (!edit) { return null; } - boolean isPrivileged = false; - // This is the first time we have seen this package name under this uid, - // so let's make sure it is valid. - if (uid != 0) { - final long ident = Binder.clearCallingIdentity(); - try { - int pkgUid = -1; - try { - ApplicationInfo appInfo = ActivityThread.getPackageManager() - .getApplicationInfo(packageName, - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - UserHandle.getUserId(uid)); - if (appInfo != null) { - pkgUid = appInfo.uid; - isPrivileged = (appInfo.privateFlags - & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; - } else { - pkgUid = resolveUid(packageName); - if (pkgUid >= 0) { - isPrivileged = false; - } - } - } catch (RemoteException e) { - Slog.w(TAG, "Could not contact PackageManager", e); - } - if (pkgUid != uid) { - // Oops! The package name is not valid for the uid they are calling - // under. Abort. - if (!uidMismatchExpected) { - RuntimeException ex = new RuntimeException("here"); - ex.fillInStackTrace(); - Slog.w(TAG, "Bad call: specified package " + packageName - + " under uid " + uid + " but it is really " + pkgUid, ex); - } - return null; - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } ops = new Ops(packageName, uidState, isPrivileged); uidState.pkgOps.put(packageName, ops); } @@ -2580,7 +2628,7 @@ public class AppOpsService extends IAppOpsService.Stub { } /** - * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>. + * Get the state of all ops for a package. * * <p>Usually callers should use {@link #getOpLocked} and not call this directly. * @@ -2638,23 +2686,15 @@ public class AppOpsService extends IAppOpsService.Stub { * @param code The code of the op * @param uid The uid the of the package * @param packageName The package name for which to get the state for + * @param isPrivileged Whether the package is privileged or not (only used if {@code edit + * == true}) * @param edit Iff {@code true} create the {@link Op} object if not yet created - * @param verifyUid Iff {@code true} check that the package belongs to the uid - * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid - * == false}) * * @return The {@link Op state} of the op */ - private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit, - boolean verifyUid, boolean isPrivileged) { - Ops ops; - - if (verifyUid) { - ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */); - } else { - ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged); - } - + private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, + boolean isPrivileged, boolean edit) { + Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged); if (ops == null) { return null; } @@ -2684,7 +2724,8 @@ public class AppOpsService extends IAppOpsService.Stub { return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid)); } - private boolean isOpRestrictedLocked(int uid, int code, String packageName) { + private boolean isOpRestrictedLocked(int uid, int code, String packageName, + boolean isPrivileged) { int userHandle = UserHandle.getUserId(uid); final int restrictionSetCount = mOpUserRestrictions.size(); @@ -2696,8 +2737,8 @@ public class AppOpsService extends IAppOpsService.Stub { if (AppOpsManager.opAllowSystemBypassRestriction(code)) { // If we are the system, bypass user restrictions for certain codes synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, + true /* edit */); if ((ops != null) && ops.isPrivileged) { return false; } @@ -3068,7 +3109,7 @@ public class AppOpsService extends IAppOpsService.Stub { out.attribute(null, "n", Integer.toString(pkg.getUid())); synchronized (this) { Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), - false /* edit */, false /* uidMismatchExpected */); + false /* isPrivileged */, false /* edit */); // Should always be present as the list of PackageOps is generated // from Ops. if (ops != null) { @@ -4647,18 +4688,8 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public void setUidMode(int code, int uid, int mode) { - AppOpsService.this.setUidMode(code, uid, mode); - } - - @Override public void setAllPkgModesToDefault(int code, int uid) { AppOpsService.this.setAllPkgModesToDefault(code, uid); } - - @Override - public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) { - return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false); - } } } diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING index a53797dfa9e0..1a5dac503463 100644 --- a/services/core/java/com/android/server/appop/TEST_MAPPING +++ b/services/core/java/com/android/server/appop/TEST_MAPPING @@ -10,6 +10,14 @@ "include-filter": "com.android.server.appop" } ] + }, + { + "name": "FrameworksMockingServicesTests", + "options": [ + { + "include-filter": "com.android.server.appop" + } + ] } ] } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 25fdf6447061..88a63f1aa06d 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6292,7 +6292,7 @@ public class AudioService extends IAudioService.Stub return false; } boolean suppress = false; - if (resolvedStream == DEFAULT_VOL_STREAM_NO_PLAYBACK && mController != null) { + if (resolvedStream != AudioSystem.STREAM_MUSIC && mController != null) { final long now = SystemClock.uptimeMillis(); if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) { // ui will become visible diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index cf83dd630a29..f15d999e1006 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -17,8 +17,10 @@ package com.android.server.compat; import android.compat.Compatibility.ChangeConfig; +import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Environment; +import android.os.RemoteException; import android.text.TextUtils; import android.util.LongArray; import android.util.LongSparseArray; @@ -26,8 +28,11 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; +import com.android.internal.compat.IOverrideValidator; +import com.android.internal.compat.OverrideAllowedState; import com.android.server.compat.config.Change; import com.android.server.compat.config.XmlParser; @@ -54,22 +59,14 @@ final class CompatConfig { private static final String TAG = "CompatConfig"; - private static final CompatConfig sInstance = new CompatConfig().initConfigFromLib( - Environment.buildPath( - Environment.getRootDirectory(), "etc", "compatconfig")); - @GuardedBy("mChanges") private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); - @VisibleForTesting - CompatConfig() { - } + private IOverrideValidator mOverrideValidator; - /** - * @return The static instance of this class to be used within the system server. - */ - static CompatConfig get() { - return sInstance; + @VisibleForTesting + CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) { + mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this); } /** @@ -159,8 +156,12 @@ final class CompatConfig { * @param enabled If the change should be enabled or disabled. * @return {@code true} if the change existed before adding the override. */ - boolean addOverride(long changeId, String packageName, boolean enabled) { + boolean addOverride(long changeId, String packageName, boolean enabled) + throws RemoteException, SecurityException { boolean alreadyKnown = true; + OverrideAllowedState allowedState = + mOverrideValidator.getOverrideAllowedState(changeId, packageName); + allowedState.enforce(changeId, packageName); synchronized (mChanges) { CompatChange c = mChanges.get(changeId); if (c == null) { @@ -186,6 +187,20 @@ final class CompatConfig { } /** + * Returns the minimum sdk version for which this change should be enabled (or 0 if it is not + * target sdk gated). + */ + int minTargetSdkForChangeId(long changeId) { + synchronized (mChanges) { + CompatChange c = mChanges.get(changeId); + if (c == null) { + return 0; + } + return c.getEnableAfterTargetSdk(); + } + } + + /** * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This * restores the default behaviour for the given change and app, once any app processes have been * restarted. @@ -194,34 +209,44 @@ final class CompatConfig { * @param packageName The app package name that was overridden. * @return {@code true} if an override existed; */ - boolean removeOverride(long changeId, String packageName) { + boolean removeOverride(long changeId, String packageName) + throws RemoteException, SecurityException { boolean overrideExists = false; synchronized (mChanges) { CompatChange c = mChanges.get(changeId); - if (c != null) { - overrideExists = true; - c.removePackageOverride(packageName); + try { + if (c != null) { + OverrideAllowedState allowedState = + mOverrideValidator.getOverrideAllowedState(changeId, packageName); + allowedState.enforce(changeId, packageName); + overrideExists = true; + c.removePackageOverride(packageName); + } + } catch (RemoteException e) { + // Should never occur, since validator is in the same process. + throw new RuntimeException("Unable to call override validator!", e); } } return overrideExists; } /** - * Overrides the enabled state for a given change and app. This method is intended to be used - * *only* for debugging purposes. + * Overrides the enabled state for a given change and app. * * <p>Note, package overrides are not persistent and will be lost on system or runtime restart. * * @param overrides list of overrides to default changes config. * @param packageName app for which the overrides will be applied. */ - void addOverrides(CompatibilityChangeConfig overrides, String packageName) { + void addOverrides(CompatibilityChangeConfig overrides, String packageName) + throws RemoteException, SecurityException { synchronized (mChanges) { for (Long changeId : overrides.enabledChanges()) { addOverride(changeId, packageName, true); } for (Long changeId : overrides.disabledChanges()) { addOverride(changeId, packageName, false); + } } } @@ -235,10 +260,22 @@ final class CompatConfig { * * @param packageName The package for which the overrides should be purged. */ - void removePackageOverrides(String packageName) { + void removePackageOverrides(String packageName) throws RemoteException, SecurityException { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { - mChanges.valueAt(i).removePackageOverride(packageName); + try { + CompatChange change = mChanges.valueAt(i); + OverrideAllowedState allowedState = + mOverrideValidator.getOverrideAllowedState(change.getId(), + packageName); + allowedState.enforce(change.getId(), packageName); + if (change != null) { + mChanges.valueAt(i).removePackageOverride(packageName); + } + } catch (RemoteException e) { + // Should never occur, since validator is in the same process. + throw new RuntimeException("Unable to call override validator!", e); + } } } } @@ -326,17 +363,23 @@ final class CompatConfig { } } - CompatConfig initConfigFromLib(File libraryDir) { + static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) { + CompatConfig config = new CompatConfig(androidBuildClassifier, context); + config.initConfigFromLib(Environment.buildPath( + Environment.getRootDirectory(), "etc", "compatconfig")); + return config; + } + + void initConfigFromLib(File libraryDir) { if (!libraryDir.exists() || !libraryDir.isDirectory()) { Slog.e(TAG, "No directory " + libraryDir + ", skipping"); - return this; + return; } for (File f : libraryDir.listFiles()) { Slog.d(TAG, "Found a config file: " + f.getPath()); //TODO(b/138222363): Handle duplicate ids across config files. readConfig(f); } - return this; } private void readConfig(File configFile) { @@ -350,4 +393,7 @@ final class CompatConfig { } } + IOverrideValidator getOverrideValidator() { + return mOverrideValidator; + } } diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java new file mode 100644 index 000000000000..4bf606e801f9 --- /dev/null +++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java @@ -0,0 +1,94 @@ +/* + * 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 com.android.server.compat; + +import static com.android.internal.compat.OverrideAllowedState.ALLOWED; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; +import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.AndroidBuildClassifier; +import com.android.internal.compat.IOverrideValidator; +import com.android.internal.compat.OverrideAllowedState; + +/** + * Implementation of the policy for allowing compat change overrides. + */ +public class OverrideValidatorImpl extends IOverrideValidator.Stub { + + private AndroidBuildClassifier mAndroidBuildClassifier; + private Context mContext; + private CompatConfig mCompatConfig; + + @VisibleForTesting + OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier, + Context context, CompatConfig config) { + mAndroidBuildClassifier = androidBuildClassifier; + mContext = context; + mCompatConfig = config; + } + + @Override + public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) { + boolean debuggableBuild = false; + boolean finalBuild = false; + int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId); + + debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild(); + finalBuild = mAndroidBuildClassifier.isFinalBuild(); + + // Allow any override for userdebug or eng builds. + if (debuggableBuild) { + return new OverrideAllowedState(ALLOWED, -1, -1); + } + PackageManager packageManager = mContext.getPackageManager(); + if (packageManager == null) { + throw new IllegalStateException("No PackageManager!"); + } + ApplicationInfo applicationInfo; + try { + applicationInfo = packageManager.getApplicationInfo(packageName, 0); + } catch (NameNotFoundException e) { + return new OverrideAllowedState(PACKAGE_DOES_NOT_EXIST, -1, -1); + } + int appTargetSdk = applicationInfo.targetSdkVersion; + // Only allow overriding debuggable apps. + if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) { + return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1); + } + // Allow overriding any change for debuggable apps on non-final builds. + if (!finalBuild) { + return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk); + } + // Do not allow overriding non-target sdk gated changes on user builds + if (minTargetSdk == -1) { + return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk); + } + // Only allow to opt-in for a targetSdk gated change. + if (applicationInfo.targetSdkVersion < minTargetSdk) { + return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk); + } + return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk); + } +} diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 4a3d7d69d874..029b7bc32ef3 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -27,9 +27,12 @@ import android.os.UserHandle; import android.util.Slog; import android.util.StatsLog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.ChangeReporter; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; +import com.android.internal.compat.IOverrideValidator; import com.android.internal.compat.IPlatformCompat; import com.android.internal.util.DumpUtils; @@ -45,11 +48,21 @@ public class PlatformCompat extends IPlatformCompat.Stub { private final Context mContext; private final ChangeReporter mChangeReporter; + private final CompatConfig mCompatConfig; public PlatformCompat(Context context) { mContext = context; mChangeReporter = new ChangeReporter( StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER); + mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext); + } + + @VisibleForTesting + PlatformCompat(Context context, CompatConfig compatConfig) { + mContext = context; + mChangeReporter = new ChangeReporter( + StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER); + mCompatConfig = compatConfig; } @Override @@ -74,7 +87,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) { - if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) { + if (mCompatConfig.isChangeEnabled(changeId, appInfo)) { reportChange(changeId, appInfo.uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED); return true; @@ -121,57 +134,59 @@ public class PlatformCompat extends IPlatformCompat.Stub { * otherwise. */ public boolean registerListener(long changeId, CompatChange.ChangeListener listener) { - return CompatConfig.get().registerListener(changeId, listener); + return mCompatConfig.registerListener(changeId, listener); } @Override - public void setOverrides(CompatibilityChangeConfig overrides, String packageName) { - CompatConfig.get().addOverrides(overrides, packageName); + public void setOverrides(CompatibilityChangeConfig overrides, String packageName) + throws RemoteException, SecurityException { + mCompatConfig.addOverrides(overrides, packageName); killPackage(packageName); } @Override - public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) { - CompatConfig.get().addOverrides(overrides, packageName); + public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) + throws RemoteException, SecurityException { + mCompatConfig.addOverrides(overrides, packageName); } @Override - public void clearOverrides(String packageName) { - CompatConfig config = CompatConfig.get(); - config.removePackageOverrides(packageName); + public void clearOverrides(String packageName) throws RemoteException, SecurityException { + mCompatConfig.removePackageOverrides(packageName); killPackage(packageName); } @Override - public void clearOverridesForTest(String packageName) { - CompatConfig config = CompatConfig.get(); - config.removePackageOverrides(packageName); + public void clearOverridesForTest(String packageName) + throws RemoteException, SecurityException { + mCompatConfig.removePackageOverrides(packageName); } @Override - public boolean clearOverride(long changeId, String packageName) { - boolean existed = CompatConfig.get().removeOverride(changeId, packageName); + public boolean clearOverride(long changeId, String packageName) + throws RemoteException, SecurityException { + boolean existed = mCompatConfig.removeOverride(changeId, packageName); killPackage(packageName); return existed; } @Override public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) { - return CompatConfig.get().getAppConfig(appInfo); + return mCompatConfig.getAppConfig(appInfo); } @Override public CompatibilityChangeInfo[] listAllChanges() { - return CompatConfig.get().dumpChanges(); + return mCompatConfig.dumpChanges(); } /** * Check whether the change is known to the compat config. - * @param changeId + * * @return {@code true} if the change is known. */ public boolean isKnownChangeId(long changeId) { - return CompatConfig.get().isKnownChangeId(changeId); + return mCompatConfig.isKnownChangeId(changeId); } @@ -181,11 +196,11 @@ public class PlatformCompat extends IPlatformCompat.Stub { * * @param appInfo The app in question * @return A sorted long array of change IDs. We use a primitive array to minimize memory - * footprint: Every app process will store this array statically so we aim to reduce - * overhead as much as possible. + * footprint: Every app process will store this array statically so we aim to reduce + * overhead as much as possible. */ public long[] getDisabledChanges(ApplicationInfo appInfo) { - return CompatConfig.get().getDisabledChanges(appInfo); + return mCompatConfig.getDisabledChanges(appInfo); } /** @@ -195,18 +210,24 @@ public class PlatformCompat extends IPlatformCompat.Stub { * @return The change ID, or {@code -1} if no change with that name exists. */ public long lookupChangeId(String name) { - return CompatConfig.get().lookupChangeId(name); + return mCompatConfig.lookupChangeId(name); } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return; - CompatConfig.get().dumpConfig(pw); + mCompatConfig.dumpConfig(pw); + } + + @Override + public IOverrideValidator getOverrideValidator() { + return mCompatConfig.getOverrideValidator(); } /** * Clears information stored about events reported on behalf of an app. * To be called once upon app start or end. A second call would be a no-op. + * * @param appInfo the app to reset */ public void resetReporting(ApplicationInfo appInfo) { diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java index 1b1c54682255..5010e46a74eb 100644 --- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java +++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java @@ -16,6 +16,9 @@ package com.android.server.connectivity; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -24,6 +27,7 @@ import android.net.ConnectivityManager; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -91,7 +95,10 @@ public class DataConnectionStats extends BroadcastReceiver { boolean visible = (simReadyOrUnknown || isCdma()) // we only check the sim state for GSM && hasService() && mDataState == TelephonyManager.DATA_CONNECTED; - int networkType = mServiceState.getDataNetworkType(); + NetworkRegistrationInfo regInfo = + mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); + int networkType = regInfo == null ? TelephonyManager.NETWORK_TYPE_UNKNOWN + : regInfo.getAccessNetworkTechnology(); if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible", networkType, visible ? "" : "not ")); try { diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 9bae902eb7b1..af8a3666e9b7 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -39,11 +39,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.ISocketKeepaliveCallback; +import android.net.InvalidPacketException; import android.net.KeepalivePacketData; import android.net.NattKeepalivePacketData; import android.net.NetworkAgent; import android.net.NetworkUtils; -import android.net.SocketKeepalive.InvalidPacketException; import android.net.SocketKeepalive.InvalidSocketException; import android.net.TcpKeepalivePacketData; import android.net.util.IpUtils; @@ -657,7 +657,10 @@ public class KeepaliveTracker { final TcpKeepalivePacketData packet; try { packet = TcpKeepaliveController.getTcpKeepalivePacket(fd); - } catch (InvalidPacketException | InvalidSocketException e) { + } catch (InvalidSocketException e) { + notifyErrorCallback(cb, e.error); + return; + } catch (InvalidPacketException e) { notifyErrorCallback(cb, e.error); return; } diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 6fa999cb039a..04c792ae482b 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -26,6 +26,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH; import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN; @@ -46,19 +47,18 @@ import android.net.NetworkIdentity; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkRequest; +import android.net.NetworkSpecifier; import android.net.NetworkStats; import android.net.NetworkTemplate; -import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; +import android.net.Uri; import android.os.BestClock; import android.os.Handler; import android.os.SystemClock; -import android.net.Uri; import android.os.UserHandle; import android.provider.Settings; import android.telephony.TelephonyManager; -import android.util.DataUnit; import android.util.DebugUtils; -import android.util.Pair; import android.util.Range; import android.util.Slog; @@ -74,7 +74,6 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; -import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -185,7 +184,6 @@ public class MultipathPolicyTracker { // Track information on mobile networks as they come and go. class MultipathTracker { final Network network; - final int subId; final String subscriberId; private long mQuota; @@ -198,13 +196,14 @@ public class MultipathPolicyTracker { public MultipathTracker(Network network, NetworkCapabilities nc) { this.network = network; this.mNetworkCapabilities = new NetworkCapabilities(nc); - try { - subId = Integer.parseInt( - ((StringNetworkSpecifier) nc.getNetworkSpecifier()).toString()); - } catch (ClassCastException | NullPointerException | NumberFormatException e) { + NetworkSpecifier specifier = nc.getNetworkSpecifier(); + int subId = INVALID_SUBSCRIPTION_ID; + if (specifier instanceof TelephonyNetworkSpecifier) { + subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); + } else { throw new IllegalStateException(String.format( - "Can't get subId from mobile network %s (%s): %s", - network, nc, e.getMessage())); + "Can't get subId from mobile network %s (%s)", + network, nc)); } TelephonyManager tele = mContext.getSystemService(TelephonyManager.class); diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index aea6d8d24312..f636d67c3d1d 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -116,7 +116,8 @@ public class Nat464Xlat extends BaseNetworkObserver { && !lp.hasIpv4Address(); // If the network tells us it doesn't use clat, respect that. - final boolean skip464xlat = (nai.netMisc() != null) && nai.netMisc().skip464xlat; + final boolean skip464xlat = (nai.netAgentConfig() != null) + && nai.netAgentConfig().skip464xlat; return supported && connected && isIpv6OnlyNetwork && !skip464xlat; } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 5e085ca293a4..d66aec576137 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -23,9 +23,9 @@ import android.net.INetd; import android.net.INetworkMonitor; import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; -import android.net.NetworkMisc; import android.net.NetworkMonitorManager; import android.net.NetworkRequest; import android.net.NetworkScore; @@ -127,7 +127,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // This should only be modified by ConnectivityService, via setNetworkCapabilities(). // TODO: make this private with a getter. public NetworkCapabilities networkCapabilities; - public final NetworkMisc networkMisc; + public final NetworkAgentConfig networkAgentConfig; // Indicates if netd has been told to create this Network. From this point on the appropriate // routing rules are setup and routes are added so packets can begin flowing over the Network. // This is a sticky bit; once set it is never cleared. @@ -261,7 +261,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, LinkProperties lp, NetworkCapabilities nc, @NonNull NetworkScore ns, Context context, - Handler handler, NetworkMisc misc, ConnectivityService connService, INetd netd, + Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) { this.messenger = messenger; asyncChannel = ac; @@ -274,7 +274,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { mConnService = connService; mContext = context; mHandler = handler; - networkMisc = misc; + networkAgentConfig = config; this.factorySerialNumber = factorySerialNumber; } @@ -309,8 +309,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { return mConnService; } - public NetworkMisc netMisc() { - return networkMisc; + public NetworkAgentConfig netAgentConfig() { + return networkAgentConfig; } public Handler handler() { @@ -451,15 +451,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { && !isLingering(); } - /** - * Returns whether this network is currently suspended. A network is suspended if it is still - * connected but data temporarily fails to transfer. See {@link NetworkInfo.State#SUSPENDED} - * and {@link NetworkCapabilities#NET_CAPABILITY_NOT_SUSPENDED}. - */ - public boolean isSuspended() { - return networkInfo.getState() == NetworkInfo.State.SUSPENDED; - } - // Does this network satisfy request? public boolean satisfies(NetworkRequest request) { return created && @@ -487,7 +478,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // selected and we're trying to see what its score could be. This ensures that we don't tear // down an explicitly selected network before the user gets a chance to prefer it when // a higher-scoring network (e.g., Ethernet) is available. - if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) { + if (networkAgentConfig.explicitlySelected + && (networkAgentConfig.acceptUnvalidated || pretendValidated)) { return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE; } @@ -533,7 +525,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { synchronized (this) { // Network objects are outwardly immutable so there is no point in duplicating. // Duplicating also precludes sharing socket factories and connection pools. - final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null; + final String subscriberId = (networkAgentConfig != null) + ? networkAgentConfig.subscriberId : null; return new NetworkState(new NetworkInfo(networkInfo), new LinkProperties(linkProperties), new NetworkCapabilities(networkCapabilities), network, subscriberId, null); @@ -641,13 +634,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { + "nc{" + networkCapabilities + "} Score{" + getCurrentScore() + "} " + "everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} " + "created{" + created + "} lingering{" + isLingering() + "} " - + "explicitlySelected{" + networkMisc.explicitlySelected + "} " - + "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " + + "explicitlySelected{" + networkAgentConfig.explicitlySelected + "} " + + "acceptUnvalidated{" + networkAgentConfig.acceptUnvalidated + "} " + "everCaptivePortalDetected{" + everCaptivePortalDetected + "} " + "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} " + "captivePortalValidationPending{" + captivePortalValidationPending + "} " + "partialConnectivity{" + partialConnectivity + "} " - + "acceptPartialConnectivity{" + networkMisc.acceptPartialConnectivity + "} " + + "acceptPartialConnectivity{" + networkAgentConfig.acceptPartialConnectivity + "} " + "clat{" + clatd + "} " + "}"; } diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 21795184b1bd..2c415570d5fa 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -28,7 +28,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.net.NetworkSpecifier; -import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiInfo; import android.os.UserHandle; import android.telephony.SubscriptionManager; @@ -223,14 +223,8 @@ public class NetworkNotificationManager { // name has been added to it NetworkSpecifier specifier = nai.networkCapabilities.getNetworkSpecifier(); int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; - if (specifier instanceof StringNetworkSpecifier) { - try { - subId = Integer.parseInt( - ((StringNetworkSpecifier) specifier).specifier); - } catch (NumberFormatException e) { - Slog.e(TAG, "NumberFormatException on " - + ((StringNetworkSpecifier) specifier).specifier); - } + if (specifier instanceof TelephonyNetworkSpecifier) { + subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); } details = mTelephonyManager.createForSubscriptionId(subId) diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java index e570ef1e9bf2..1129899ee3ff 100644 --- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java +++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java @@ -30,8 +30,8 @@ import static android.system.OsConstants.IP_TTL; import static android.system.OsConstants.TIOCOUTQ; import android.annotation.NonNull; +import android.net.InvalidPacketException; import android.net.NetworkUtils; -import android.net.SocketKeepalive.InvalidPacketException; import android.net.SocketKeepalive.InvalidSocketException; import android.net.TcpKeepalivePacketData; import android.net.TcpKeepalivePacketDataParcelable; diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 09790c46972e..69ab47a61362 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -53,11 +53,11 @@ import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.net.Network; import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; -import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkMisc; +import android.net.NetworkProvider; import android.net.RouteInfo; import android.net.UidRange; import android.net.VpnService; @@ -848,7 +848,7 @@ public class Vpn { } public int getNetId() { - return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET; + return mNetworkAgent != null ? mNetworkAgent.network.netId : NETID_UNSET; } private LinkProperties makeLinkProperties() { @@ -914,7 +914,7 @@ public class Vpn { * has certain changes, in which case this method would just return {@code false}. */ private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) { - // NetworkMisc cannot be updated without registering a new NetworkAgent. + // NetworkAgentConfig cannot be updated without registering a new NetworkAgent. if (oldConfig.allowBypass != mConfig.allowBypass) { Log.i(TAG, "Handover not possible due to changes to allowBypass"); return false; @@ -947,8 +947,8 @@ public class Vpn { mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null); - NetworkMisc networkMisc = new NetworkMisc(); - networkMisc.allowBypass = mConfig.allowBypass && !mLockdown; + NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig(); + networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown; mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid()); mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle, @@ -957,8 +957,8 @@ public class Vpn { try { mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */, mNetworkInfo, mNetworkCapabilities, lp, - ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc, - NetworkFactory.SerialNumber.VPN) { + ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig, + NetworkProvider.ID_VPN) { @Override public void unwanted() { // We are user controlled, not driven by NetworkRequest. diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index fa8c48bdc7f7..a89daff2d3bb 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -86,7 +86,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; -import android.text.format.Time; +import android.text.format.TimeMigrationUtils; import android.util.EventLog; import android.util.Log; import android.util.Pair; @@ -1987,9 +1987,7 @@ public class SyncManager { if (time == 0) { return "N/A"; } - Time tobj = new Time(); - tobj.set(time); - return tobj.format("%Y-%m-%d %H:%M:%S"); + return TimeMigrationUtils.formatMillisWithFixedFormat(time); } private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> { @@ -2555,9 +2553,7 @@ public class SyncManager { accountKey = "Unknown"; } final long elapsedTime = item.elapsedTime; - final Time time = new Time(); final long eventTime = item.eventTime; - time.set(eventTime); final String key = authorityName + "/" + accountKey; final Long lastEventTime = lastTimeMap.get(key); @@ -2622,9 +2618,7 @@ public class SyncManager { authorityName = "Unknown"; accountKey = "Unknown"; } - final Time time = new Time(); final long eventTime = item.eventTime; - time.set(eventTime); pw.printf(" #%-3d: %s %8s ", i + 1, diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 1fc0db3ff7cb..6dcfadef5f8c 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -76,7 +76,7 @@ public class DisplayModeDirector { private static final int GLOBAL_ID = -1; // The tolerance within which we consider something approximately equals. - private static final float EPSILON = 0.001f; + private static final float EPSILON = 0.01f; private final Object mLock = new Object(); private final Context mContext; diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 63302705b36f..69cbc22f41bf 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -3454,7 +3454,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } /** - * This is kept due to {@link android.annotation.UnsupportedAppUsage} in + * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage} in * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in * {@link InputMethodService#onCreate()}. * diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index eb5d472f7fbc..e655b35d930f 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -29,7 +29,7 @@ import android.net.Network; import android.net.Uri; import android.os.RemoteException; import android.os.UserHandle; -import android.text.format.Time; +import android.text.format.TimeMigrationUtils; import android.util.ArraySet; import android.util.Pair; import android.util.Slog; @@ -1643,17 +1643,13 @@ public final class JobStatus { if (numFailures != 0) { pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures); } - final Time t = new Time(); - final String format = "%Y-%m-%d %H:%M:%S"; if (mLastSuccessfulRunTime != 0) { pw.print(prefix); pw.print("Last successful run: "); - t.set(mLastSuccessfulRunTime); - pw.println(t.format(format)); + pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastSuccessfulRunTime)); } if (mLastFailedRunTime != 0) { pw.print(prefix); pw.print("Last failed run: "); - t.set(mLastFailedRunTime); - pw.println(t.format(format)); + pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastFailedRunTime)); } } diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java index ababad961c2d..97df55706bf8 100644 --- a/services/core/java/com/android/server/job/controllers/TimeController.java +++ b/services/core/java/com/android/server/job/controllers/TimeController.java @@ -325,8 +325,7 @@ public final class TimeController extends StateController { && !wouldBeReadyWithConstraintLocked( job, JobStatus.CONSTRAINT_TIMING_DELAY)) { if (DEBUG) { - Slog.i(TAG, - "Skipping " + job + " because delay won't make it ready."); + Slog.i(TAG, "Skipping " + job + " because delay won't make it ready."); } continue; } @@ -385,7 +384,8 @@ public final class TimeController extends StateController { /** * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's * delay will expire. - * This alarm <b>will</b> wake up the phone. + * This alarm <b>will not</b> wake up the phone if + * {@link TcConstants#USE_NON_WAKEUP_ALARM_FOR_DELAY} is true. */ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); @@ -393,8 +393,11 @@ public final class TimeController extends StateController { return; } mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis; - updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener, - mNextDelayExpiredElapsedMillis, ws); + final int alarmType = + mTcConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY + ? AlarmManager.ELAPSED_REALTIME : AlarmManager.ELAPSED_REALTIME_WAKEUP; + updateAlarmWithListenerLocked(DELAY_TAG, alarmType, + mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis, ws); } /** @@ -408,16 +411,16 @@ public final class TimeController extends StateController { return; } mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis; - updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener, - mNextJobExpiredElapsedMillis, ws); + updateAlarmWithListenerLocked(DEADLINE_TAG, AlarmManager.ELAPSED_REALTIME_WAKEUP, + mDeadlineExpiredListener, mNextJobExpiredElapsedMillis, ws); } private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) { return Math.max(proposedAlarmTimeElapsedMillis, sElapsedRealtimeClock.millis()); } - private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener, - long alarmTimeElapsed, WorkSource ws) { + private void updateAlarmWithListenerLocked(String tag, @AlarmManager.AlarmType int alarmType, + OnAlarmListener listener, long alarmTimeElapsed, WorkSource ws) { ensureAlarmServiceLocked(); if (alarmTimeElapsed == Long.MAX_VALUE) { mAlarmService.cancel(listener); @@ -425,7 +428,7 @@ public final class TimeController extends StateController { if (DEBUG) { Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed); } - mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed, + mAlarmService.set(alarmType, alarmTimeElapsed, AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws); } } @@ -464,8 +467,11 @@ public final class TimeController extends StateController { private final KeyValueListParser mParser = new KeyValueListParser(','); private static final String KEY_SKIP_NOT_READY_JOBS = "skip_not_ready_jobs"; + private static final String KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY = + "use_non_wakeup_delay_alarm"; private static final boolean DEFAULT_SKIP_NOT_READY_JOBS = true; + private static final boolean DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY = true; /** * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't @@ -474,6 +480,12 @@ public final class TimeController extends StateController { public boolean SKIP_NOT_READY_JOBS = DEFAULT_SKIP_NOT_READY_JOBS; /** + * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't + * ready now. + */ + public boolean USE_NON_WAKEUP_ALARM_FOR_DELAY = DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY; + + /** * Creates a content observer. * * @param handler The handler to run {@link #onChange} on, or null if none. @@ -510,6 +522,12 @@ public final class TimeController extends StateController { recheckAlarmsLocked(); } } + + USE_NON_WAKEUP_ALARM_FOR_DELAY = mParser.getBoolean( + KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY); + // Intentionally not calling checkExpiredDelaysAndResetAlarm() here. There's no need to + // iterate through the entire list again for this constant change. The next delay alarm + // that is set will make use of the new constant value. } private void dump(IndentingPrintWriter pw) { @@ -517,12 +535,16 @@ public final class TimeController extends StateController { pw.println("TimeController:"); pw.increaseIndent(); pw.printPair(KEY_SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS).println(); + pw.printPair(KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, + USE_NON_WAKEUP_ALARM_FOR_DELAY).println(); pw.decreaseIndent(); } private void dump(ProtoOutputStream proto) { final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER); proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS); + proto.write(ConstantsProto.TimeController.USE_NON_WAKEUP_ALARM_FOR_DELAY, + USE_NON_WAKEUP_ALARM_FOR_DELAY); proto.end(tcToken); } } diff --git a/services/core/java/com/android/server/location/NtpTimeHelper.java b/services/core/java/com/android/server/location/NtpTimeHelper.java index 296b500eacee..88e9b50bb298 100644 --- a/services/core/java/com/android/server/location/NtpTimeHelper.java +++ b/services/core/java/com/android/server/location/NtpTimeHelper.java @@ -130,7 +130,8 @@ class NtpTimeHelper { // force refresh NTP cache when outdated boolean refreshSuccess = true; - if (mNtpTime.getCacheAge() >= NTP_INTERVAL) { + NtpTrustedTime.TimeResult ntpResult = mNtpTime.getCachedTimeResult(); + if (ntpResult == null || ntpResult.getAgeMillis() >= NTP_INTERVAL) { // Blocking network operation. refreshSuccess = mNtpTime.forceRefresh(); } @@ -140,17 +141,17 @@ class NtpTimeHelper { // only update when NTP time is fresh // If refreshSuccess is false, cacheAge does not drop down. - if (mNtpTime.getCacheAge() < NTP_INTERVAL) { - long time = mNtpTime.getCachedNtpTime(); - long timeReference = mNtpTime.getCachedNtpTimeReference(); - long certainty = mNtpTime.getCacheCertainty(); + ntpResult = mNtpTime.getCachedTimeResult(); + if (ntpResult != null && ntpResult.getAgeMillis() < NTP_INTERVAL) { + long time = ntpResult.getTimeMillis(); + long timeReference = ntpResult.getElapsedRealtimeMillis(); + long certainty = ntpResult.getCertaintyMillis(); if (DEBUG) { long now = System.currentTimeMillis(); Log.d(TAG, "NTP server returned: " - + time + " (" + new Date(time) - + ") reference: " + timeReference - + " certainty: " + certainty + + time + " (" + new Date(time) + ")" + + " ntpResult: " + ntpResult + " system time offset: " + (time - now)); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java index 7f650ee7e138..b24a938ef7ea 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java @@ -18,8 +18,10 @@ package com.android.server.net; import static com.android.server.net.NetworkPolicyManagerService.isUidNetworkingBlockedInternal; +import android.annotation.NonNull; import android.net.Network; import android.net.NetworkTemplate; +import android.net.netstats.provider.AbstractNetworkStatsProvider; import android.telephony.SubscriptionPlan; import java.util.Set; @@ -126,4 +128,12 @@ public abstract class NetworkPolicyManagerInternal { */ public abstract void setMeteredRestrictedPackagesAsync( Set<String> packageNames, int userId); + + /** + * Notifies that any of the {@link AbstractNetworkStatsProvider} has reached its quota + * which was set through {@link AbstractNetworkStatsProvider#setLimit(String, long)}. + * + * @param tag the human readable identifier of the custom network stats provider. + */ + public abstract void onStatsProviderLimitReached(@NonNull String tag); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index e3e6d9d80827..9760185ca6df 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -75,6 +75,7 @@ import static android.net.NetworkTemplate.MATCH_MOBILE; import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.TrafficStats.MB_IN_BYTES; +import static android.net.netstats.provider.AbstractNetworkStatsProvider.QUOTA_UNLIMITED; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETPOLICY_OVERRIDE_ENABLED; import static android.provider.Settings.Global.NETPOLICY_QUOTA_ENABLED; @@ -160,7 +161,7 @@ import android.net.NetworkStack; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkTemplate; -import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.net.TrafficStats; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; @@ -168,6 +169,7 @@ import android.os.BestClock; import android.os.Binder; import android.os.Environment; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IDeviceIdleController; import android.os.INetworkManagementService; @@ -227,7 +229,6 @@ import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Preconditions; import com.android.internal.util.StatLogger; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -388,6 +389,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_SUBSCRIPTION_OVERRIDE = 16; private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17; private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18; + private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19; + private static final int MSG_STATS_PROVIDER_LIMIT_REACHED = 20; private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -874,7 +877,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Listen for subscriber changes mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener( - new OnSubscriptionsChangedListener(mHandler.getLooper()) { + new HandlerExecutor(mHandler), + new OnSubscriptionsChangedListener() { @Override public void onSubscriptionsChanged() { updateNetworksInternal(); @@ -2867,17 +2871,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void onTetheringChanged(String iface, boolean tethering) { - // No need to enforce permission because setRestrictBackground() will do it. - synchronized (mUidRulesFirstLock) { - if (mRestrictBackground && tethering) { - Log.d(TAG, "Tethering on (" + iface +"); disable Data Saver"); - setRestrictBackground(false); - } - } - } - - @Override public void setRestrictBackground(boolean restrictBackground) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackground"); try { @@ -3038,12 +3031,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Verify they're not lying about package name mAppOps.checkPackage(callingUid, callingPackage); + final SubscriptionManager sm; final SubscriptionInfo si; final PersistableBundle config; final long token = Binder.clearCallingIdentity(); try { - si = mContext.getSystemService(SubscriptionManager.class) - .getActiveSubscriptionInfo(subId); + sm = mContext.getSystemService(SubscriptionManager.class); + si = sm.getActiveSubscriptionInfo(subId); config = mCarrierConfigManager.getConfigForSubId(subId); } finally { Binder.restoreCallingIdentity(token); @@ -3051,7 +3045,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // First check: is caller the CarrierService? if (si != null) { - if (si.isEmbedded() && si.canManageSubscription(mContext, callingPackage)) { + if (si.isEmbedded() && sm.canManageSubscription(si, callingPackage)) { return; } } @@ -3091,6 +3085,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(MANAGE_SUBSCRIPTION_PLANS, TAG); } + private void enforceSubscriptionPlanValidity(SubscriptionPlan[] plans) { + // nothing to check if no plans + if (plans.length == 0) { + return; + } + + long applicableNetworkTypes = 0; + boolean allNetworks = false; + for (SubscriptionPlan plan : plans) { + if (plan.getNetworkTypes() == null) { + allNetworks = true; + } else { + if ((applicableNetworkTypes & plan.getNetworkTypesBitMask()) != 0) { + throw new IllegalArgumentException( + "Multiple subscription plans defined for a single network type."); + } else { + applicableNetworkTypes |= plan.getNetworkTypesBitMask(); + } + } + } + + // ensure at least one plan applies for every network type + if (!allNetworks) { + throw new IllegalArgumentException( + "No generic subscription plan that applies to all network types."); + } + } + @Override public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); @@ -3255,6 +3277,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); + enforceSubscriptionPlanValidity(plans); for (SubscriptionPlan plan : plans) { Objects.requireNonNull(plan); @@ -3283,6 +3306,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); mContext.sendBroadcast(intent, android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS); + mHandler.sendMessage( + mHandler.obtainMessage(MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans)); } finally { Binder.restoreCallingIdentity(token); } @@ -4476,6 +4501,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void dispatchSubscriptionPlansChanged(INetworkPolicyListener listener, int subId, + SubscriptionPlan[] plans) { + if (listener != null) { + try { + listener.onSubscriptionPlansChanged(subId, plans); + } catch (RemoteException ignored) { + } + } + } + private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { @@ -4501,19 +4536,36 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mListeners.finishBroadcast(); return true; } + case MSG_STATS_PROVIDER_LIMIT_REACHED: { + mNetworkStats.forceUpdate(); + + synchronized (mNetworkPoliciesSecondLock) { + // Some providers might hit the limit reached event prior to others. Thus, + // re-calculate and update interface quota for every provider is needed. + updateNetworkRulesNL(); + updateNetworkEnabledNL(); + updateNotificationsNL(); + } + return true; + } case MSG_LIMIT_REACHED: { final String iface = (String) msg.obj; - synchronized (mNetworkPoliciesSecondLock) { - if (mMeteredIfaces.contains(iface)) { - // force stats update to make sure we have - // numbers that caused alert to trigger. - mNetworkStats.forceUpdate(); - - updateNetworkEnabledNL(); - updateNotificationsNL(); + // fast return if not needed. + if (!mMeteredIfaces.contains(iface)) { + return true; } } + + // force stats update to make sure the service have the numbers that caused + // alert to trigger. + mNetworkStats.forceUpdate(); + + synchronized (mNetworkPoliciesSecondLock) { + updateNetworkRulesNL(); + updateNetworkEnabledNL(); + updateNotificationsNL(); + } return true; } case MSG_RESTRICT_BACKGROUND_CHANGED: { @@ -4556,14 +4608,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return true; } case MSG_UPDATE_INTERFACE_QUOTA: { - removeInterfaceQuota((String) msg.obj); + final String iface = (String) msg.obj; // int params need to be stitched back into a long - setInterfaceQuota((String) msg.obj, - ((long) msg.arg1 << 32) | (msg.arg2 & 0xFFFFFFFFL)); + final long quota = ((long) msg.arg1 << 32) | (msg.arg2 & 0xFFFFFFFFL); + removeInterfaceQuota(iface); + setInterfaceQuota(iface, quota); + mNetworkStats.setStatsProviderLimit(iface, quota); return true; } case MSG_REMOVE_INTERFACE_QUOTA: { - removeInterfaceQuota((String) msg.obj); + final String iface = (String) msg.obj; + removeInterfaceQuota(iface); + mNetworkStats.setStatsProviderLimit(iface, QUOTA_UNLIMITED); return true; } case MSG_RESET_FIREWALL_RULES_BY_UID: { @@ -4594,6 +4650,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { setNetworkTemplateEnabledInner(template, enabled); return true; } + case MSG_SUBSCRIPTION_PLANS_CHANGED: { + final SubscriptionPlan[] plans = (SubscriptionPlan[]) msg.obj; + final int subId = msg.arg1; + final int length = mListeners.beginBroadcast(); + for (int i = 0; i < length; i++) { + final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); + dispatchSubscriptionPlansChanged(listener, subId, plans); + } + mListeners.finishBroadcast(); + return true; + } default: { return false; } @@ -5203,6 +5270,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mHandler.obtainMessage(MSG_METERED_RESTRICTED_PACKAGES_CHANGED, userId, 0, packageNames).sendToTarget(); } + + @Override + public void onStatsProviderLimitReached(@NonNull String tag) { + Log.v(TAG, "onStatsProviderLimitReached: " + tag); + mHandler.obtainMessage(MSG_STATS_PROVIDER_LIMIT_REACHED).sendToTarget(); + } } private void setMeteredRestrictedPackagesInternal(Set<String> packageNames, int userId) { @@ -5231,16 +5304,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private int parseSubId(NetworkState state) { - // TODO: moved to using a legitimate NetworkSpecifier instead of string parsing int subId = INVALID_SUBSCRIPTION_ID; if (state != null && state.networkCapabilities != null && state.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier(); - if (spec instanceof StringNetworkSpecifier) { - try { - subId = Integer.parseInt(((StringNetworkSpecifier) spec).specifier); - } catch (NumberFormatException e) { - } + if (spec instanceof TelephonyNetworkSpecifier) { + subId = ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); } } return subId; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 3ca1803262e7..22b01bee6c6a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -229,7 +229,7 @@ public class NetworkStatsFactory { entry.txPackets += reader.nextLong(); } - stats.addValues(entry); + stats.addEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -279,7 +279,7 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - stats.addValues(entry); + stats.addEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -439,7 +439,7 @@ public class NetworkStatsFactory { if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) && (limitUid == UID_ALL || limitUid == entry.uid) && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.addValues(entry); + stats.addEntry(entry); } reader.finishLine(); diff --git a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java index 4843ede7219d..6d72cb5ee345 100644 --- a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java @@ -16,6 +16,7 @@ package com.android.server.net; +import android.annotation.NonNull; import android.net.NetworkStats; import android.net.NetworkTemplate; @@ -34,4 +35,10 @@ public abstract class NetworkStatsManagerInternal { /** Force update of statistics. */ public abstract void forceUpdate(); + + /** + * Set the quota limit to all registered custom network stats providers. + * Note that invocation of any interface will be sent to all providers. + */ + public abstract void setStatsProviderLimit(@NonNull String iface, long quota); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index a41fb7d32762..fc39a253bc24 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -18,6 +18,7 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; +import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; @@ -27,6 +28,7 @@ import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.IFACE_VT; import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.ROAMING_ALL; @@ -70,6 +72,7 @@ import static com.android.server.NetworkManagementSocketTagger.resetKernelUidSta import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; @@ -96,6 +99,9 @@ import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.net.netstats.provider.INetworkStatsProvider; +import android.net.netstats.provider.INetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProviderCallback; import android.os.BestClock; import android.os.Binder; import android.os.DropBoxManager; @@ -108,6 +114,7 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -175,7 +182,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * This avoids firing the global alert too often on devices with high transfer speeds and * high quota. */ - private static final int PERFORM_POLL_DELAY_MS = 1000; + private static final int DEFAULT_PERFORM_POLL_DELAY_MS = 1000; private static final String TAG_NETSTATS_ERROR = "netstats_error"; @@ -211,13 +218,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Virtual network interface for video telephony. This is for VT data usage counting purpose. */ - public static final String VT_INTERFACE = "vt_data0"; + // TODO: Remove this after no one is using it. + public static final String VT_INTERFACE = NetworkStats.IFACE_VT; /** * Settings that can be changed externally. */ public interface NetworkStatsSettings { public long getPollInterval(); + public long getPollDelay(); public boolean getSampleEnabled(); public boolean getAugmentEnabled(); @@ -246,6 +255,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private final Object mStatsLock = new Object(); + private final Object mStatsProviderLock = new Object(); /** Set of currently active ifaces. */ @GuardedBy("mStatsLock") @@ -270,6 +280,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); + private final RemoteCallbackList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList = + new RemoteCallbackList<>(); + @GuardedBy("mStatsLock") private NetworkStatsRecorder mDevRecorder; @GuardedBy("mStatsLock") @@ -500,9 +513,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Register for a global alert that is delivered through - * {@link INetworkManagementEventObserver} once a threshold amount of data - * has been transferred. + * Register for a global alert that is delivered through {@link INetworkManagementEventObserver} + * or {@link NetworkStatsProviderCallback#onAlertReached()} once a threshold amount of data has + * been transferred. */ private void registerGlobalAlert() { try { @@ -512,6 +525,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (RemoteException e) { // ignored; service lives in system_server } + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setAlert(mGlobalAlertBytes)); } @Override @@ -712,7 +726,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, + stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets, entry.operations)); return stats; @@ -801,8 +815,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void incrementOperationCount(int uid, int tag, int operationCount) { if (Binder.getCallingUid() != uid) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.UPDATE_DEVICE_STATS, TAG); + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); } if (operationCount < 0) { @@ -1093,7 +1106,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Observer that watches for {@link INetworkManagementService} alerts. */ - private INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() { + private final INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() { @Override public void limitReached(String limitName, String iface) { // only someone like NMS should be calling us @@ -1104,7 +1117,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // such a call pending; UID stats are handled during normal polling interval. if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, - PERFORM_POLL_DELAY_MS); + mSettings.getPollDelay()); } } } @@ -1179,8 +1192,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), ident.getRoaming(), true /* metered */, true /* onDefaultNetwork */); - findOrCreateNetworkIdentitySet(mActiveIfaces, VT_INTERFACE).add(vtIdent); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, VT_INTERFACE).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); } if (isMobile) { @@ -1250,6 +1263,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { xtSnapshot.combineAllValues(tetherSnapshot); devSnapshot.combineAllValues(tetherSnapshot); + // Snapshot for dev/xt stats from all custom stats providers. Counts per-interface data + // from stats providers that isn't already counted by dev and XT stats. + Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider"); + final NetworkStats providersnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); + Trace.traceEnd(TRACE_TAG_NETWORK); + xtSnapshot.combineAllValues(providersnapshot); + devSnapshot.combineAllValues(providersnapshot); + // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic // can't be reattributed to responsible apps. Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev"); @@ -1353,6 +1374,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performSampleLocked(); } + // request asynchronous stats update from all providers for next poll. + // TODO: request with a valid token. + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */)); + // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -1474,6 +1499,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void forceUpdate() { NetworkStatsService.this.forceUpdate(); } + + @Override + public void setStatsProviderLimit(@NonNull String iface, long quota) { + Slog.v(TAG, "setStatsProviderLimit(" + iface + "," + quota + ")"); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setLimit(iface, quota)); + } } @Override @@ -1688,6 +1719,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { uidSnapshot.combineAllValues(vtStats); } + // 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); + uidSnapshot.combineAllValues(providerStats); + uidSnapshot.combineAllValues(mUidOperations); return uidSnapshot; @@ -1724,6 +1761,152 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + /** + * Registers a custom provider of {@link android.net.NetworkStats} to combine the network + * statistics that cannot be seen by the kernel to system. To unregister, invoke the + * {@code unregister()} of the returned callback. + * + * @param tag a human readable identifier of the custom network stats provider. + * @param provider the binder interface of + * {@link android.net.netstats.provider.AbstractNetworkStatsProvider} that + * needs to be registered to the system. + * + * @return a binder interface of + * {@link android.net.netstats.provider.NetworkStatsProviderCallback}, which can be + * used to report events to the system. + */ + public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( + @NonNull String tag, @NonNull INetworkStatsProvider provider) { + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + Objects.requireNonNull(provider, "provider is null"); + Objects.requireNonNull(tag, "tag is null"); + try { + NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( + tag, provider, mAlertObserver, mStatsProviderCbList); + mStatsProviderCbList.register(callback); + Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" + + getCallingUid() + "/" + getCallingPid()); + return callback; + } catch (RemoteException e) { + Log.e(TAG, "registerNetworkStatsProvider failed", e); + } + return null; + } + + // Collect stats from local cache of providers. + private @NonNull NetworkStats getNetworkStatsFromProviders(int how) { + final NetworkStats ret = new NetworkStats(0L, 0); + invokeForAllStatsProviderCallbacks((cb) -> ret.combineAllValues(cb.getCachedStats(how))); + return ret; + } + + @FunctionalInterface + private interface ThrowingConsumer<S, T extends Throwable> { + void accept(S s) throws T; + } + + private void invokeForAllStatsProviderCallbacks( + @NonNull ThrowingConsumer<NetworkStatsProviderCallbackImpl, RemoteException> task) { + synchronized (mStatsProviderCbList) { + final int length = mStatsProviderCbList.beginBroadcast(); + try { + for (int i = 0; i < length; i++) { + final NetworkStatsProviderCallbackImpl cb = + mStatsProviderCbList.getBroadcastItem(i); + try { + task.accept(cb); + } catch (RemoteException e) { + Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); + } + } + } finally { + mStatsProviderCbList.finishBroadcast(); + } + } + } + + private static class NetworkStatsProviderCallbackImpl extends INetworkStatsProviderCallback.Stub + implements IBinder.DeathRecipient { + @NonNull final String mTag; + @NonNull private final Object mProviderStatsLock = new Object(); + @NonNull final INetworkStatsProvider mProvider; + @NonNull final INetworkManagementEventObserver mAlertObserver; + @NonNull final RemoteCallbackList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList; + + @GuardedBy("mProviderStatsLock") + // STATS_PER_IFACE and STATS_PER_UID + private final NetworkStats mIfaceStats = new NetworkStats(0L, 0); + @GuardedBy("mProviderStatsLock") + private final NetworkStats mUidStats = new NetworkStats(0L, 0); + + NetworkStatsProviderCallbackImpl( + @NonNull String tag, @NonNull INetworkStatsProvider provider, + @NonNull INetworkManagementEventObserver alertObserver, + @NonNull RemoteCallbackList<NetworkStatsProviderCallbackImpl> cbList) + throws RemoteException { + mTag = tag; + mProvider = provider; + mProvider.asBinder().linkToDeath(this, 0); + mAlertObserver = alertObserver; + mStatsProviderCbList = cbList; + } + + @NonNull + public NetworkStats getCachedStats(int how) { + synchronized (mProviderStatsLock) { + NetworkStats stats; + switch (how) { + case STATS_PER_IFACE: + stats = mIfaceStats; + break; + case STATS_PER_UID: + stats = mUidStats; + break; + default: + throw new IllegalArgumentException("Invalid type: " + how); + } + // Return a defensive copy instead of local reference. + return stats.clone(); + } + } + + @Override + public void onStatsUpdated(int token, @Nullable NetworkStats ifaceStats, + @Nullable NetworkStats uidStats) { + // TODO: 1. Use token to map ifaces to correct NetworkIdentity. + // 2. Store the difference and store it directly to the recorder. + synchronized (mProviderStatsLock) { + if (ifaceStats != null) mIfaceStats.combineAllValues(ifaceStats); + if (uidStats != null) mUidStats.combineAllValues(uidStats); + } + } + + @Override + public void onAlertReached() throws RemoteException { + mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */); + } + + @Override + public void onLimitReached() { + Log.d(TAG, mTag + ": onLimitReached"); + LocalServices.getService(NetworkPolicyManagerInternal.class) + .onStatsProviderLimitReached(mTag); + } + + @Override + public void binderDied() { + Log.d(TAG, mTag + ": binderDied"); + mStatsProviderCbList.unregister(this); + } + + @Override + public void unregister() { + Log.d(TAG, mTag + ": unregister"); + mStatsProviderCbList.unregister(this); + } + + } + @VisibleForTesting static class HandlerCallback implements Handler.Callback { private final NetworkStatsService mService; @@ -1813,6 +1996,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } @Override + public long getPollDelay() { + return DEFAULT_PERFORM_POLL_DELAY_MS; + } + @Override public long getGlobalAlertBytes(long def) { return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def); } diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java index 9c1ac346ce32..947405ed2a78 100644 --- a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java +++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java @@ -56,16 +56,17 @@ public final class DeviceIdentifiersPolicyService extends SystemService { // for any device / profile owner checks. The majority of requests for the serial number // should use the getSerialForPackage method with the calling package specified. if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext, - /* callingPackage */ null, "getSerial")) { + /* callingPackage */ null, null, "getSerial")) { return Build.UNKNOWN; } return SystemProperties.get("ro.serialno", Build.UNKNOWN); } @Override - public @Nullable String getSerialForPackage(String callingPackage) throws RemoteException { + public @Nullable String getSerialForPackage(String callingPackage, + String callingFeatureId) throws RemoteException { if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext, - callingPackage, "getSerial")) { + callingPackage, callingFeatureId, "getSerial")) { return Build.UNKNOWN; } return SystemProperties.get("ro.serialno", Build.UNKNOWN); diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index e991a91fe8ba..609a41560e7b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1159,7 +1159,7 @@ class PackageManagerShellCommand extends ShellCommand { } abandonSession = false; - if (!params.sessionParams.isStaged || !params.waitForStagedSessionReady) { + if (!params.sessionParams.isStaged || !params.mWaitForStagedSessionReady) { pw.println("Success"); return 0; } @@ -1197,7 +1197,7 @@ class PackageManagerShellCommand extends ShellCommand { + si.getStagedSessionErrorMessage() + "]"); return 1; } - pw.println("Success"); + pw.println("Success. Reboot device to apply staged session"); return 0; } finally { if (abandonSession) { @@ -2487,7 +2487,7 @@ class PackageManagerShellCommand extends ShellCommand { SessionParams sessionParams; String installerPackageName; int userId = UserHandle.USER_ALL; - boolean waitForStagedSessionReady = false; + boolean mWaitForStagedSessionReady = true; long timeoutMs = DEFAULT_WAIT_MS; } @@ -2615,13 +2615,16 @@ class PackageManagerShellCommand extends ShellCommand { sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; break; case "--wait": - params.waitForStagedSessionReady = true; + params.mWaitForStagedSessionReady = true; try { params.timeoutMs = Long.parseLong(peekNextArg()); getNextArg(); } catch (NumberFormatException ignore) { } break; + case "--no-wait": + params.mWaitForStagedSessionReady = false; + break; default: throw new IllegalArgumentException("Unknown option " + opt); } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 2d8a2acd575f..ebba128b5f28 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -79,7 +79,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManagerInternal; import android.text.TextUtils; -import android.text.format.Time; +import android.text.format.TimeMigrationUtils; import android.util.ArraySet; import android.util.AtomicFile; import android.util.KeyValueListParser; @@ -3981,9 +3981,7 @@ public class ShortcutService extends IShortcutService.Stub { } static String formatTime(long time) { - Time tobj = new Time(); - tobj.set(time); - return tobj.format("%Y-%m-%d %H:%M:%S"); + return TimeMigrationUtils.formatMillisWithFixedFormat(time); } private void dumpCurrentTime(PrintWriter pw) { diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 2705455078ff..349a0031613b 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -41,6 +41,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.ParcelableException; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; @@ -414,29 +415,28 @@ public class StagingManager { } else { params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; } - int apkSessionId = mPi.createSession( - params, originalSession.getInstallerPackageName(), - 0 /* UserHandle.SYSTEM */); - PackageInstallerSession apkSession = mPi.getSession(apkSessionId); - try { + int apkSessionId = mPi.createSession( + params, originalSession.getInstallerPackageName(), + 0 /* UserHandle.SYSTEM */); + PackageInstallerSession apkSession = mPi.getSession(apkSessionId); apkSession.open(); for (String apkFilePath : apkFilePaths) { File apkFile = new File(apkFilePath); ParcelFileDescriptor pfd = ParcelFileDescriptor.open(apkFile, ParcelFileDescriptor.MODE_READ_ONLY); - long sizeBytes = pfd.getStatSize(); + long sizeBytes = (pfd == null) ? -1 : pfd.getStatSize(); if (sizeBytes < 0) { Slog.e(TAG, "Unable to get size of: " + apkFilePath); return null; } apkSession.write(apkFile.getName(), 0, sizeBytes, pfd); } - } catch (IOException e) { + return apkSession; + } catch (IOException | ParcelableException e) { Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e); return null; } - return apkSession; } private boolean commitApkSession(@NonNull PackageInstallerSession apkSession, diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index f56231fc02af..9e86a4bd2880 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -229,6 +229,7 @@ public class DexManager { // If the dex file is the primary apk (or a split) and not isUsedByOtherApps // do not record it. This case does not bring any new usable information // and can be safely skipped. + dexPathIndex++; continue; } diff --git a/services/core/java/com/android/server/stats/OWNERS b/services/core/java/com/android/server/stats/OWNERS index 8d7f8822f78e..fc7fd220b26a 100644 --- a/services/core/java/com/android/server/stats/OWNERS +++ b/services/core/java/com/android/server/stats/OWNERS @@ -1,9 +1,8 @@ -bookatz@google.com -cjyu@google.com -dwchen@google.com +jeffreyhuang@google.com joeo@google.com +muhammadq@google.com +ruchirr@google.com singhtejinder@google.com -stlafon@google.com +tsaichristine@google.com yaochen@google.com -yanglu@google.com -yro@google.com
\ No newline at end of file +yro@google.com diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java index 172367a128cc..b7d63609cff9 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.timedetector.ITimeDetectorService; import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.NetworkTimeSuggestion; import android.app.timedetector.PhoneTimeSuggestion; import android.content.ContentResolver; import android.content.Context; @@ -105,6 +106,14 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { mHandler.post(() -> mTimeDetectorStrategy.suggestManualTime(timeSignal)); } + @Override + public void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) { + enforceSuggestNetworkTimePermission(); + Objects.requireNonNull(timeSignal); + + mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal)); + } + @VisibleForTesting public void handleAutoTimeDetectionToggle() { mHandler.post(mTimeDetectorStrategy::handleAutoTimeDetectionChanged); @@ -119,10 +128,20 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { } private void enforceSuggestPhoneTimePermission() { - mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time"); + mContext.enforceCallingPermission( + android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE, + "suggest phone time and time zone"); } private void enforceSuggestManualTimePermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SET_TIME, "set time"); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE, + "suggest manual time and time zone"); + } + + private void enforceSuggestNetworkTimePermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.SET_TIME, + "set time"); } } diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java index 0a6c2e776072..468b806d6dce 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java @@ -19,9 +19,9 @@ package com.android.server.timedetector; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.NetworkTimeSuggestion; import android.app.timedetector.PhoneTimeSuggestion; -import android.content.Intent; -import android.util.TimestampedValue; +import android.os.TimestampedValue; import java.io.PrintWriter; @@ -61,10 +61,10 @@ public interface TimeDetectorStrategy { /** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */ void acquireWakeLock(); - /** Returns the elapsedRealtimeMillis clock value. The WakeLock must be held. */ + /** Returns the elapsedRealtimeMillis clock value. */ long elapsedRealtimeMillis(); - /** Returns the system clock value. The WakeLock must be held. */ + /** Returns the system clock value. */ long systemClockMillis(); /** Sets the device system clock. The WakeLock must be held. */ @@ -72,9 +72,6 @@ public interface TimeDetectorStrategy { /** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */ void releaseWakeLock(); - - /** Send the supplied intent as a stick broadcast. */ - void sendStickyBroadcast(@NonNull Intent intent); } /** Initialize the strategy. */ @@ -86,6 +83,9 @@ public interface TimeDetectorStrategy { /** Process the suggested manually entered time. */ void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion); + /** Process the suggested time from network sources. */ + void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion); + /** Handle the auto-time setting being toggled on or off. */ void handleAutoTimeDetectionChanged(); diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java index 42d59d51c6af..19484db149b1 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java @@ -20,11 +20,9 @@ import android.annotation.NonNull; import android.app.AlarmManager; import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; @@ -90,13 +88,11 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat @Override public long elapsedRealtimeMillis() { - checkWakeLockHeld(); return SystemClock.elapsedRealtime(); } @Override public long systemClockMillis() { - checkWakeLockHeld(); return System.currentTimeMillis(); } @@ -112,11 +108,6 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat mWakeLock.release(); } - @Override - public void sendStickyBroadcast(@NonNull Intent intent) { - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - private void checkWakeLockHeld() { if (!mWakeLock.isHeld()) { Slog.wtf(TAG, "WakeLock " + mWakeLock + " not held"); diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java index c50248d4b402..e95fc4a4a938 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java @@ -21,17 +21,17 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.NetworkTimeSuggestion; import android.app.timedetector.PhoneTimeSuggestion; -import android.content.Intent; -import android.telephony.TelephonyManager; +import android.os.TimestampedValue; import android.util.LocalLog; import android.util.Slog; -import android.util.TimestampedValue; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.server.timezonedetector.ArrayMapWithHistory; +import com.android.server.timezonedetector.ReferenceWithHistory; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -56,11 +56,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { /** Each bucket is this size. All buckets are equally sized. */ @VisibleForTesting static final int PHONE_BUCKET_SIZE_MILLIS = 60 * 60 * 1000; - /** Phone suggestions older than this value are considered too old. */ + /** Phone and network suggestions older than this value are considered too old to be used. */ @VisibleForTesting - static final long PHONE_MAX_AGE_MILLIS = PHONE_BUCKET_COUNT * PHONE_BUCKET_SIZE_MILLIS; + static final long MAX_UTC_TIME_AGE_MILLIS = PHONE_BUCKET_COUNT * PHONE_BUCKET_SIZE_MILLIS; - @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL }) + @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL, ORIGIN_NETWORK }) @Retention(RetentionPolicy.SOURCE) public @interface Origin {} @@ -72,6 +72,10 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { @Origin private static final int ORIGIN_MANUAL = 2; + /** Used when a time value originated from a network signal. */ + @Origin + private static final int ORIGIN_NETWORK = 3; + /** * CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the * actual system clock time before a warning is logged. Used to help identify situations where @@ -101,9 +105,13 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { * will have a small number of telephony devices and phoneIds are assumed to be stable. */ @GuardedBy("this") - private ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionByPhoneId = + private final ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionByPhoneId = new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); + @GuardedBy("this") + private final ReferenceWithHistory<NetworkTimeSuggestion> mLastNetworkSuggestion = + new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); + @Override public void initialize(@NonNull Callback callback) { mCallback = callback; @@ -122,6 +130,19 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } @Override + public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion) { + if (!validateSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) { + return; + } + mLastNetworkSuggestion.set(timeSuggestion); + + // Now perform auto time detection. The new suggestion may be used to modify the system + // clock. + String reason = "New network time suggested. timeSuggestion=" + timeSuggestion; + doAutoTimeDetection(reason); + } + + @Override public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) { // Empty time suggestion means that telephony network connectivity has been lost. // The passage of time is relentless, and we don't expect our users to use a time machine, @@ -167,6 +188,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { ipw.increaseIndent(); // level 1 ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet); + ipw.println("mCallback.isAutoTimeDetectionEnabled()=" + + mCallback.isAutoTimeDetectionEnabled()); + ipw.println("mCallback.elapsedRealtimeMillis()=" + mCallback.elapsedRealtimeMillis()); + ipw.println("mCallback.systemClockMillis()=" + mCallback.systemClockMillis()); + ipw.println("mCallback.systemClockUpdateThresholdMillis()=" + + mCallback.systemClockUpdateThresholdMillis()); ipw.println("Time change log:"); ipw.increaseIndent(); // level 2 @@ -178,6 +205,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { mSuggestionByPhoneId.dump(ipw); ipw.decreaseIndent(); // level 2 + ipw.println("Network suggestion history:"); + ipw.increaseIndent(); // level 2 + mLastNetworkSuggestion.dump(ipw); + ipw.decreaseIndent(); // level 2 + ipw.decreaseIndent(); // level 1 ipw.flush(); } @@ -247,23 +279,34 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { return; } + // Android devices currently prioritize any telephony over network signals. There are + // carrier compliance tests that would need to be changed before we could ignore NITZ or + // prefer NTP generally. This check is cheap on devices without phone hardware. PhoneTimeSuggestion bestPhoneSuggestion = findBestPhoneSuggestion(); + if (bestPhoneSuggestion != null) { + final TimestampedValue<Long> newUtcTime = bestPhoneSuggestion.getUtcTime(); + String cause = "Found good phone suggestion." + + ", bestPhoneSuggestion=" + bestPhoneSuggestion + + ", detectionReason=" + detectionReason; + setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, cause); + return; + } - // Work out what to do with the best suggestion. - if (bestPhoneSuggestion == null) { - // There is no good phone suggestion. - if (DBG) { - Slog.d(LOG_TAG, "Could not determine time: No best phone suggestion." - + " detectionReason=" + detectionReason); - } + // There is no good phone suggestion, try network. + NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion(); + if (networkSuggestion != null) { + final TimestampedValue<Long> newUtcTime = networkSuggestion.getUtcTime(); + String cause = "Found good network suggestion." + + ", networkSuggestion=" + networkSuggestion + + ", detectionReason=" + detectionReason; + setSystemClockIfRequired(ORIGIN_NETWORK, newUtcTime, cause); return; } - final TimestampedValue<Long> newUtcTime = bestPhoneSuggestion.getUtcTime(); - String cause = "Found good suggestion." - + ", bestPhoneSuggestion=" + bestPhoneSuggestion - + ", detectionReason=" + detectionReason; - setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, cause); + if (DBG) { + Slog.d(LOG_TAG, "Could not determine time: No best phone or network suggestion." + + " detectionReason=" + detectionReason); + } } @GuardedBy("this") @@ -342,37 +385,50 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { private static int scorePhoneSuggestion( long elapsedRealtimeMillis, @NonNull PhoneTimeSuggestion timeSuggestion) { - // The score is based on the age since receipt. Suggestions are bucketed so two - // suggestions in the same bucket from different phoneIds are scored the same. + + // Validate first. TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime(); - long referenceTimeMillis = utcTime.getReferenceTimeMillis(); - if (referenceTimeMillis > elapsedRealtimeMillis) { - // Future times are ignored. They imply the reference time was wrong, or the elapsed - // realtime clock has gone backwards, neither of which are supportable situations. - Slog.w(LOG_TAG, "Existing suggestion found to be in the future. " + if (!validateSuggestionUtcTime(elapsedRealtimeMillis, utcTime)) { + Slog.w(LOG_TAG, "Existing suggestion found to be invalid " + " elapsedRealtimeMillis=" + elapsedRealtimeMillis + ", timeSuggestion=" + timeSuggestion); return PHONE_INVALID_SCORE; } - long ageMillis = elapsedRealtimeMillis - referenceTimeMillis; + // The score is based on the age since receipt. Suggestions are bucketed so two + // suggestions in the same bucket from different phoneIds are scored the same. + long ageMillis = elapsedRealtimeMillis - utcTime.getReferenceTimeMillis(); - // Any suggestion > MAX_AGE_MILLIS is treated as too old. Although time is relentless and - // predictable, the accuracy of the reference time clock may be poor over long periods which - // would lead to errors creeping in. Also, in edge cases where a bad suggestion has been - // made and never replaced, it could also mean that the time detection code remains - // opinionated using a bad invalid suggestion. This caps that edge case at MAX_AGE_MILLIS. - if (ageMillis > PHONE_MAX_AGE_MILLIS) { + // Turn the age into a discrete value: 0 <= bucketIndex < PHONE_BUCKET_COUNT. + int bucketIndex = (int) (ageMillis / PHONE_BUCKET_SIZE_MILLIS); + if (bucketIndex >= PHONE_BUCKET_COUNT) { return PHONE_INVALID_SCORE; } - // Turn the age into a discrete value: 0 <= bucketIndex < MAX_AGE_HOURS. - int bucketIndex = (int) (ageMillis / PHONE_BUCKET_SIZE_MILLIS); - // We want the lowest bucket index to have the highest score. 0 > score >= BUCKET_COUNT. return PHONE_BUCKET_COUNT - bucketIndex; } + /** Returns the latest, valid, network suggestion. Returns {@code null} if there isn't one. */ + @GuardedBy("this") + @Nullable + private NetworkTimeSuggestion findLatestValidNetworkSuggestion() { + NetworkTimeSuggestion networkSuggestion = mLastNetworkSuggestion.get(); + if (networkSuggestion == null) { + // No network suggestions received. This is normal if there's no connectivity. + return null; + } + + TimestampedValue<Long> utcTime = networkSuggestion.getUtcTime(); + long elapsedRealTimeMillis = mCallback.elapsedRealtimeMillis(); + if (!validateSuggestionUtcTime(elapsedRealTimeMillis, utcTime)) { + // The latest suggestion is not valid, usually due to its age. + return null; + } + + return networkSuggestion; + } + @GuardedBy("this") private void setSystemClockIfRequired( @Origin int origin, @NonNull TimestampedValue<Long> time, @NonNull String cause) { @@ -409,7 +465,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } private static boolean isOriginAutomatic(@Origin int origin) { - return origin == ORIGIN_PHONE; + return origin != ORIGIN_MANUAL; } @GuardedBy("this") @@ -477,17 +533,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } else { mLastAutoSystemClockTimeSet = null; } - - // Historically, Android has sent a TelephonyManager.ACTION_NETWORK_SET_TIME broadcast only - // when setting the time using NITZ. - if (origin == ORIGIN_PHONE) { - // Send a broadcast that telephony code used to send after setting the clock. - // TODO Remove this broadcast as soon as there are no remaining listeners. - Intent intent = new Intent(TelephonyManager.ACTION_NETWORK_SET_TIME); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra("time", newSystemClockMillis); - mCallback.sendStickyBroadcast(intent); - } } /** @@ -501,6 +546,16 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } /** + * Returns the latest valid network suggestion. Not intended for general use: it is used during + * tests to check strategy behavior. + */ + @VisibleForTesting + @Nullable + public NetworkTimeSuggestion findLatestValidNetworkSuggestionForTests() { + return findLatestValidNetworkSuggestion(); + } + + /** * A method used to inspect state during tests. Not intended for general use. */ @VisibleForTesting @@ -508,4 +563,32 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int phoneId) { return mSuggestionByPhoneId.get(phoneId); } + + /** + * A method used to inspect state during tests. Not intended for general use. + */ + @VisibleForTesting + @Nullable + public NetworkTimeSuggestion getLatestNetworkSuggestion() { + return mLastNetworkSuggestion.get(); + } + + private static boolean validateSuggestionUtcTime( + long elapsedRealtimeMillis, TimestampedValue<Long> utcTime) { + long referenceTimeMillis = utcTime.getReferenceTimeMillis(); + if (referenceTimeMillis > elapsedRealtimeMillis) { + // Future reference times are ignored. They imply the reference time was wrong, or the + // elapsed realtime clock used to derive it has gone backwards, neither of which are + // supportable situations. + return false; + } + + // Any suggestion > MAX_AGE_MILLIS is treated as too old. Although time is relentless and + // predictable, the accuracy of the reference time clock may be poor over long periods which + // would lead to errors creeping in. Also, in edge cases where a bad suggestion has been + // made and never replaced, it could also mean that the time detection code remains + // opinionated using a bad invalid suggestion. This caps that edge case at MAX_AGE_MILLIS. + long ageMillis = elapsedRealtimeMillis - referenceTimeMillis; + return ageMillis <= MAX_UTC_TIME_AGE_MILLIS; + } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 18ed51a6cd5e..5b58199aec4f 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -1814,8 +1814,8 @@ public final class TvInputManagerService extends SystemService { } @Override - public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info, int device) - throws RemoteException { + public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info, + @TvInputManager.DvbDeviceType int deviceType) throws RemoteException { if (mContext.checkCallingPermission(android.Manifest.permission.DVB_DEVICE) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires DVB_DEVICE permission"); @@ -1852,7 +1852,7 @@ public final class TvInputManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { String deviceFileName; - switch (device) { + switch (deviceType) { case TvInputManager.DVB_DEVICE_DEMUX: deviceFileName = String.format(dvbDeviceFound ? "/dev/dvb/adapter%d/demux%d" : "/dev/dvb%d.demux%d", @@ -1869,14 +1869,14 @@ public final class TvInputManagerService extends SystemService { info.getAdapterId(), info.getDeviceId()); break; default: - throw new IllegalArgumentException("Invalid DVB device: " + device); + throw new IllegalArgumentException("Invalid DVB device: " + deviceType); } try { // The DVB frontend device only needs to be opened in read/write mode, which // allows performing tuning operations. The DVB demux and DVR device are enough // to be opened in read only mode. return ParcelFileDescriptor.open(new File(deviceFileName), - TvInputManager.DVB_DEVICE_FRONTEND == device + TvInputManager.DVB_DEVICE_FRONTEND == deviceType ? ParcelFileDescriptor.MODE_READ_WRITE : ParcelFileDescriptor.MODE_READ_ONLY); } catch (FileNotFoundException e) { diff --git a/services/core/java/com/android/server/wallpaper/GLHelper.java b/services/core/java/com/android/server/wallpaper/GLHelper.java new file mode 100644 index 000000000000..1d733f53f055 --- /dev/null +++ b/services/core/java/com/android/server/wallpaper/GLHelper.java @@ -0,0 +1,148 @@ +/* + * 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 com.android.server.wallpaper; + +import static android.opengl.EGL14.EGL_ALPHA_SIZE; +import static android.opengl.EGL14.EGL_BLUE_SIZE; +import static android.opengl.EGL14.EGL_CONFIG_CAVEAT; +import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; +import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY; +import static android.opengl.EGL14.EGL_DEPTH_SIZE; +import static android.opengl.EGL14.EGL_GREEN_SIZE; +import static android.opengl.EGL14.EGL_HEIGHT; +import static android.opengl.EGL14.EGL_NONE; +import static android.opengl.EGL14.EGL_NO_CONTEXT; +import static android.opengl.EGL14.EGL_NO_DISPLAY; +import static android.opengl.EGL14.EGL_NO_SURFACE; +import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; +import static android.opengl.EGL14.EGL_RED_SIZE; +import static android.opengl.EGL14.EGL_RENDERABLE_TYPE; +import static android.opengl.EGL14.EGL_STENCIL_SIZE; +import static android.opengl.EGL14.EGL_WIDTH; +import static android.opengl.EGL14.eglChooseConfig; +import static android.opengl.EGL14.eglCreateContext; +import static android.opengl.EGL14.eglCreatePbufferSurface; +import static android.opengl.EGL14.eglDestroyContext; +import static android.opengl.EGL14.eglDestroySurface; +import static android.opengl.EGL14.eglGetDisplay; +import static android.opengl.EGL14.eglGetError; +import static android.opengl.EGL14.eglInitialize; +import static android.opengl.EGL14.eglMakeCurrent; +import static android.opengl.EGL14.eglTerminate; +import static android.opengl.GLES20.GL_MAX_TEXTURE_SIZE; +import static android.opengl.GLES20.glGetIntegerv; + +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLSurface; +import android.opengl.GLUtils; +import android.os.SystemProperties; +import android.util.Log; + +class GLHelper { + private static final String TAG = GLHelper.class.getSimpleName(); + private static final int sMaxTextureSize; + + static { + int maxTextureSize = SystemProperties.getInt("sys.max_texture_size", 0); + sMaxTextureSize = maxTextureSize > 0 ? maxTextureSize : retrieveTextureSizeFromGL(); + } + + private static int retrieveTextureSizeFromGL() { + try { + String err; + + // Before we can retrieve info from GL, + // we have to create EGLContext, EGLConfig and EGLDisplay first. + // We will fail at querying info from GL once one of above failed. + // When this happens, we will use defValue instead. + EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay == null || eglDisplay == EGL_NO_DISPLAY) { + err = "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + if (!eglInitialize(eglDisplay, null, 0 /* majorOffset */, null, 1 /* minorOffset */)) { + err = "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + EGLConfig eglConfig = null; + int[] configsCount = new int[1]; + EGLConfig[] configs = new EGLConfig[1]; + int[] configSpec = new int[] { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_NONE + }; + + if (!eglChooseConfig(eglDisplay, configSpec, 0 /* attrib_listOffset */, + configs, 0 /* configOffset */, 1 /* config_size */, + configsCount, 0 /* num_configOffset */)) { + err = "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } else if (configsCount[0] > 0) { + eglConfig = configs[0]; + } + + if (eglConfig == null) { + throw new RuntimeException("eglConfig not initialized!"); + } + + int[] attr_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + EGLContext eglContext = eglCreateContext( + eglDisplay, eglConfig, EGL_NO_CONTEXT, attr_list, 0 /* offset */); + + if (eglContext == null || eglContext == EGL_NO_CONTEXT) { + err = "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + // We create a push buffer temporarily for querying info from GL. + int[] attrs = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + EGLSurface eglSurface = + eglCreatePbufferSurface(eglDisplay, eglConfig, attrs, 0 /* offset */); + eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + + // Now, we are ready to query the info from GL. + int[] maxSize = new int[1]; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0 /* offset */); + + // We have got the info we want, release all egl resources. + eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(eglDisplay, eglSurface); + eglDestroyContext(eglDisplay, eglContext); + eglTerminate(eglDisplay); + return maxSize[0]; + } catch (RuntimeException e) { + Log.w(TAG, "Retrieve from GL failed", e); + return Integer.MAX_VALUE; + } + } + + static int getMaxTextureSize() { + return sMaxTextureSize; + } +} + diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index b0f1e5d69be4..991c09a97bf5 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -134,6 +134,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private static final boolean DEBUG = false; private static final boolean DEBUG_LIVE = true; + // This 100MB limitation is defined in RecordingCanvas. + private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; + public static class Lifecycle extends SystemService { private IWallpaperManagerService mService; @@ -572,7 +575,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Only generate crop for default display. final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY); - Rect cropHint = new Rect(wallpaper.cropHint); + final Rect cropHint = new Rect(wallpaper.cropHint); + final DisplayInfo displayInfo = new DisplayInfo(); + mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); if (DEBUG) { Slog.v(TAG, "Generating crop for new wallpaper(s): 0x" @@ -618,12 +623,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } // scale if the crop height winds up not matching the recommended metrics - needScale = (wpData.mHeight != cropHint.height()); + needScale = wpData.mHeight != cropHint.height() + || cropHint.height() > GLHelper.getMaxTextureSize() + || cropHint.width() > GLHelper.getMaxTextureSize(); //make sure screen aspect ratio is preserved if width is scaled under screen size if (needScale) { - final DisplayInfo displayInfo = new DisplayInfo(); - mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height(); final int newWidth = (int) (cropHint.width() * scaleByHeight); if (newWidth < displayInfo.logicalWidth) { @@ -644,14 +649,29 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (!needCrop && !needScale) { // Simple case: the nominal crop fits what we want, so we take // the whole thing and just copy the image file directly. - if (DEBUG) { - Slog.v(TAG, "Null crop of new wallpaper; copying"); + + // TODO: It is not accurate to estimate bitmap size without decoding it, + // may be we can try to remove this optimized way in the future, + // that means, we will always go into the 'else' block. + + // This is just a quick estimation, may be smaller than it is. + long estimateSize = options.outWidth * options.outHeight * 4; + + // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. + // Please see: RecordingCanvas#throwIfCannotDraw. + if (estimateSize < MAX_BITMAP_SIZE) { + success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); } - success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); + if (!success) { wallpaper.cropFile.delete(); // TODO: fall back to default wallpaper in this case } + + if (DEBUG) { + Slog.v(TAG, "Null crop of new wallpaper, estimate size=" + + estimateSize + ", success=" + success); + } } else { // Fancy case: crop and scale. First, we decode and scale down if appropriate. FileOutputStream f = null; @@ -665,49 +685,78 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // We calculate the largest power-of-two under the actual ratio rather than // just let the decode take care of it because we also want to remap where the // cropHint rectangle lies in the decoded [super]rect. - final BitmapFactory.Options scaler; final int actualScale = cropHint.height() / wpData.mHeight; int scale = 1; - while (2*scale < actualScale) { + while (2 * scale <= actualScale) { scale *= 2; } - if (scale > 1) { - scaler = new BitmapFactory.Options(); - scaler.inSampleSize = scale; + options.inSampleSize = scale; + options.inJustDecodeBounds = false; + + final Rect estimateCrop = new Rect(cropHint); + estimateCrop.scale(1f / options.inSampleSize); + final float hRatio = (float) wpData.mHeight / estimateCrop.height(); + final int destHeight = (int) (estimateCrop.height() * hRatio); + final int destWidth = (int) (estimateCrop.width() * hRatio); + + // We estimated an invalid crop, try to adjust the cropHint to get a valid one. + if (destWidth > GLHelper.getMaxTextureSize()) { + int newHeight = (int) (wpData.mHeight / hRatio); + int newWidth = (int) (wpData.mWidth / hRatio); + if (DEBUG) { - Slog.v(TAG, "Downsampling cropped rect with scale " + scale); + Slog.v(TAG, "Invalid crop dimensions, trying to adjust."); } - } else { - scaler = null; + + estimateCrop.set(cropHint); + estimateCrop.left += (cropHint.width() - newWidth) / 2; + estimateCrop.top += (cropHint.height() - newHeight) / 2; + estimateCrop.right = estimateCrop.left + newWidth; + estimateCrop.bottom = estimateCrop.top + newHeight; + cropHint.set(estimateCrop); + estimateCrop.scale(1f / options.inSampleSize); + } + + // We've got the safe cropHint; now we want to scale it properly to + // the desired rectangle. + // That's a height-biased operation: make it fit the hinted height. + final int safeHeight = (int) (estimateCrop.height() * hRatio); + final int safeWidth = (int) (estimateCrop.width() * hRatio); + + if (DEBUG) { + Slog.v(TAG, "Decode parameters:"); + Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop); + Slog.v(TAG, " down sampling=" + options.inSampleSize + + ", hRatio=" + hRatio); + Slog.v(TAG, " dest=" + destWidth + "x" + destHeight); + Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight); + Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize()); } - Bitmap cropped = decoder.decodeRegion(cropHint, scaler); + + Bitmap cropped = decoder.decodeRegion(cropHint, options); decoder.recycle(); if (cropped == null) { Slog.e(TAG, "Could not decode new wallpaper"); } else { - // We've got the extracted crop; now we want to scale it properly to - // the desired rectangle. That's a height-biased operation: make it - // fit the hinted height, and accept whatever width we end up with. - cropHint.offsetTo(0, 0); - cropHint.right /= scale; // adjust by downsampling factor - cropHint.bottom /= scale; - final float heightR = - ((float) wpData.mHeight) / ((float) cropHint.height()); - if (DEBUG) { - Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint); - } - final int destWidth = (int)(cropHint.width() * heightR); + // We are safe to create final crop with safe dimensions now. final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, - destWidth, wpData.mHeight, true); + safeWidth, safeHeight, true); if (DEBUG) { Slog.v(TAG, "Final extract:"); Slog.v(TAG, " dims: w=" + wpData.mWidth + " h=" + wpData.mHeight); - Slog.v(TAG, " out: w=" + finalCrop.getWidth() + Slog.v(TAG, " out: w=" + finalCrop.getWidth() + " h=" + finalCrop.getHeight()); } + // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. + // Please see: RecordingCanvas#throwIfCannotDraw. + if (finalCrop.getByteCount() > MAX_BITMAP_SIZE) { + throw new RuntimeException( + "Too large bitmap, limit=" + MAX_BITMAP_SIZE); + } + f = new FileOutputStream(wallpaper.cropFile); bos = new BufferedOutputStream(f, 32*1024); finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos); @@ -1981,6 +2030,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (!isWallpaperSupported(callingPackage)) { return; } + + // Make sure both width and height are not larger than max texture size. + width = Math.min(width, GLHelper.getMaxTextureSize()); + height = Math.min(height, GLHelper.getMaxTextureSize()); + synchronized (mLock) { int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 2b1c07ba40b1..3b66c72c1025 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -124,6 +124,7 @@ cc_defaults { "android.hardware.thermal@1.0", "android.hardware.tv.cec@1.0", "android.hardware.tv.input@1.0", + "android.hardware.vibrator-cpp", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", @@ -133,7 +134,6 @@ cc_defaults { "android.frameworks.sensorservice@1.0", "android.system.suspend@1.0", "suspend_control_aidl_interface-cpp", - "vintf-vibrator-cpp", ], static_libs: [ diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp index 9cd743b3466a..8b6526ff49f0 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp @@ -20,6 +20,7 @@ #include <inttypes.h> #include <sys/stat.h> #include <sys/types.h> +#include <vector> #include <jni.h> diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 4d4a7b41643c..0275f3ea32f7 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -33,7 +33,6 @@ #include "bpf/BpfUtils.h" #include "netdbpf/BpfNetworkStats.h" -using android::bpf::Stats; using android::bpf::bpfGetUidStats; using android::bpf::bpfGetIfaceStats; @@ -54,7 +53,7 @@ enum StatsType { TCP_TX_PACKETS = 5 }; -static uint64_t getStatsType(struct Stats* stats, StatsType type) { +static uint64_t getStatsType(Stats* stats, StatsType type) { switch (type) { case RX_BYTES: return stats->rxBytes; @@ -73,7 +72,7 @@ static uint64_t getStatsType(struct Stats* stats, StatsType type) { } } -static int parseIfaceStats(const char* iface, struct Stats* stats) { +static int parseIfaceStats(const char* iface, Stats* stats) { FILE *fp = fopen(QTAGUID_IFACE_STATS, "r"); if (fp == NULL) { return -1; @@ -117,7 +116,7 @@ static int parseIfaceStats(const char* iface, struct Stats* stats) { return 0; } -static int parseUidStats(const uint32_t uid, struct Stats* stats) { +static int parseUidStats(const uint32_t uid, Stats* stats) { FILE *fp = fopen(QTAGUID_UID_STATS, "r"); if (fp == NULL) { return -1; @@ -150,8 +149,7 @@ static int parseUidStats(const uint32_t uid, struct Stats* stats) { } static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) { - struct Stats stats; - memset(&stats, 0, sizeof(Stats)); + Stats stats = {}; if (useBpfStats) { if (bpfGetIfaceStats(NULL, &stats) == 0) { @@ -175,8 +173,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type, return UNKNOWN; } - struct Stats stats; - memset(&stats, 0, sizeof(Stats)); + Stats stats = {}; if (useBpfStats) { if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) { @@ -194,8 +191,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type, } static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) { - struct Stats stats; - memset(&stats, 0, sizeof(Stats)); + Stats stats = {}; if (useBpfStats) { if (bpfGetUidStats(uid, &stats) == 0) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 127b8e016d15..952a64cb2d7c 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -206,6 +206,7 @@ import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; import android.provider.Settings; import android.provider.Settings.Global; +import android.provider.Telephony; import android.security.IKeyChainAliasCallback; import android.security.IKeyChainService; import android.security.KeyChain; @@ -246,6 +247,7 @@ import com.android.internal.telephony.SmsApplication; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; +import com.android.internal.util.FunctionalUtils.ThrowingSupplier; import com.android.internal.util.JournaledFile; import com.android.internal.util.Preconditions; import com.android.internal.util.StatLogger; @@ -2061,6 +2063,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Binder.withCleanCallingIdentity(action); } + final <T> T binderWithCleanCallingIdentity(@NonNull ThrowingSupplier<T> action) { + return Binder.withCleanCallingIdentity(action); + } + final int userHandleGetCallingUserId() { return UserHandle.getUserId(binderGetCallingUid()); } @@ -13936,23 +13942,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkNotNull(apnSetting, "ApnSetting is null in addOverrideApn"); enforceDeviceOwner(who); - int operatedId = -1; - Uri resultUri; - final long id = mInjector.binderClearCallingIdentity(); - try { - resultUri = mContext.getContentResolver().insert(DPC_URI, apnSetting.toContentValues()); - } finally { - mInjector.binderRestoreCallingIdentity(id); - } - if (resultUri != null) { - try { - operatedId = Integer.parseInt(resultUri.getLastPathSegment()); - } catch (NumberFormatException e) { - Slog.e(LOG_TAG, "Failed to parse inserted override APN id.", e); - } + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null) { + return mInjector.binderWithCleanCallingIdentity( + () -> tm.addDevicePolicyOverrideApn(mContext, apnSetting)); + } else { + Log.w(LOG_TAG, "TelephonyManager is null when trying to add override apn"); + return Telephony.Carriers.INVALID_APN_ID; } - - return operatedId; } @Override @@ -13968,13 +13965,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (apnId < 0) { return false; } - final long id = mInjector.binderClearCallingIdentity(); - try { - return mContext.getContentResolver().update( - Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), - apnSetting.toContentValues(), null, null) > 0; - } finally { - mInjector.binderRestoreCallingIdentity(id); + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null) { + return mInjector.binderWithCleanCallingIdentity( + () -> tm.modifyDevicePolicyOverrideApn(mContext, apnId, apnSetting)); + } else { + Log.w(LOG_TAG, "TelephonyManager is null when trying to modify override apn"); + return false; } } @@ -14016,28 +14013,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private List<ApnSetting> getOverrideApnsUnchecked() { - final Cursor cursor; - final long id = mInjector.binderClearCallingIdentity(); - try { - cursor = mContext.getContentResolver().query(DPC_URI, null, null, null, null); - } finally { - mInjector.binderRestoreCallingIdentity(id); - } - - if (cursor == null) { - return Collections.emptyList(); - } - try { - List<ApnSetting> apnList = new ArrayList<ApnSetting>(); - cursor.moveToPosition(-1); - while (cursor.moveToNext()) { - ApnSetting apn = ApnSetting.makeApnSetting(cursor); - apnList.add(apn); - } - return apnList; - } finally { - cursor.close(); + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null) { + return mInjector.binderWithCleanCallingIdentity( + () -> tm.getDevicePolicyOverrideApns(mContext)); } + Log.w(LOG_TAG, "TelephonyManager is null when trying to get override apns"); + return Collections.emptyList(); } @Override diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b5b21f4189b4..c56634146c7b 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1695,7 +1695,7 @@ public final class SystemServer { if (!isWatch && !disableNetworkTime) { traceBeginAndSlog("StartNetworkTimeUpdateService"); try { - networkTimeUpdater = new NetworkTimeUpdateServiceImpl(context); + networkTimeUpdater = new NetworkTimeUpdateService(context); ServiceManager.addService("network_time_update_service", networkTimeUpdater); } catch (Throwable e) { reportWtf("starting NetworkTimeUpdate service", e); diff --git a/services/net/Android.bp b/services/net/Android.bp index 9c7cfc197bba..cf84bdfb5b6f 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -23,7 +23,6 @@ filegroup { name: "services-tethering-shared-srcs", srcs: [ ":framework-annotations", - "java/android/net/util/NetdService.java", "java/android/net/util/NetworkConstants.java", ], visibility: ["//frameworks/base/packages/Tethering"], diff --git a/services/net/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java index 7f2f499ab21f..aad75ae16aa9 100644 --- a/services/net/java/android/net/TcpKeepalivePacketData.java +++ b/services/net/java/android/net/TcpKeepalivePacketData.java @@ -19,7 +19,6 @@ import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.SocketKeepalive.InvalidPacketException; import android.net.util.IpUtils; import android.os.Parcel; import android.os.Parcelable; diff --git a/services/net/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java index 61cd88aac921..c93e5c5e4759 100644 --- a/services/net/java/android/net/ip/IpClientCallbacks.java +++ b/services/net/java/android/net/ip/IpClientCallbacks.java @@ -17,6 +17,7 @@ package android.net.ip; import android.net.DhcpResults; +import android.net.DhcpResultsParcelable; import android.net.Layer2PacketParcelable; import android.net.LinkProperties; @@ -69,6 +70,18 @@ public class IpClientCallbacks { public void onNewDhcpResults(DhcpResults dhcpResults) {} /** + * Callback called when new DHCP results are available. + * + * <p>This is purely advisory and not an indication of provisioning success or failure. This is + * only here for callers that want to expose DHCPv4 results to other APIs + * (e.g., WifiInfo#setInetAddress). + * + * <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not + * the passed-in DhcpResults object is null. + */ + public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {} + + /** * Indicates that provisioning was successful. */ public void onProvisioningSuccess(LinkProperties newLp) {} diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java index 4d60e6239376..7f723b1c232b 100644 --- a/services/net/java/android/net/ip/IpClientUtil.java +++ b/services/net/java/android/net/ip/IpClientUtil.java @@ -119,6 +119,7 @@ public class IpClientUtil { @Override public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) { mCb.onNewDhcpResults(fromStableParcelable(dhcpResults)); + mCb.onNewDhcpResults(dhcpResults); } @Override diff --git a/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java b/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java index a8a258fc5ff7..9c5d4ad6ceeb 100644 --- a/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java +++ b/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java @@ -3,6 +3,7 @@ package com.android.server.location; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import android.os.Looper; import android.os.SystemClock; @@ -52,8 +53,10 @@ public class NtpTimeHelperTest { @Test public void handleInjectNtpTime_cachedAgeLow_injectTime() throws InterruptedException { - doReturn(NtpTimeHelper.NTP_INTERVAL - 1).when(mMockNtpTrustedTime).getCacheAge(); - doReturn(MOCK_NTP_TIME).when(mMockNtpTrustedTime).getCachedNtpTime(); + NtpTrustedTime.TimeResult result = mock(NtpTrustedTime.TimeResult.class); + doReturn(NtpTimeHelper.NTP_INTERVAL - 1).when(result).getAgeMillis(); + doReturn(MOCK_NTP_TIME).when(result).getTimeMillis(); + doReturn(result).when(mMockNtpTrustedTime).getCachedTimeResult(); mNtpTimeHelper.retrieveAndInjectNtpTime(); @@ -64,7 +67,9 @@ public class NtpTimeHelperTest { @Test public void handleInjectNtpTime_injectTimeFailed_injectTimeDelayed() throws InterruptedException { - doReturn(NtpTimeHelper.NTP_INTERVAL + 1).when(mMockNtpTrustedTime).getCacheAge(); + NtpTrustedTime.TimeResult result1 = mock(NtpTrustedTime.TimeResult.class); + doReturn(NtpTimeHelper.NTP_INTERVAL + 1).when(result1).getAgeMillis(); + doReturn(result1).when(mMockNtpTrustedTime).getCachedTimeResult(); doReturn(false).when(mMockNtpTrustedTime).forceRefresh(); mNtpTimeHelper.retrieveAndInjectNtpTime(); @@ -72,8 +77,10 @@ public class NtpTimeHelperTest { assertThat(mCountDownLatch.await(2, TimeUnit.SECONDS)).isFalse(); doReturn(true).when(mMockNtpTrustedTime).forceRefresh(); - doReturn(1L).when(mMockNtpTrustedTime).getCacheAge(); - doReturn(MOCK_NTP_TIME).when(mMockNtpTrustedTime).getCachedNtpTime(); + NtpTrustedTime.TimeResult result2 = mock(NtpTrustedTime.TimeResult.class); + doReturn(1L).when(result2).getAgeMillis(); + doReturn(MOCK_NTP_TIME).when(result2).getTimeMillis(); + doReturn(result2).when(mMockNtpTrustedTime).getCachedTimeResult(); SystemClock.sleep(NtpTimeHelper.RETRY_INTERVAL); waitForTasksToBePostedOnHandlerAndRunThem(); diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml index 32d7d026ff10..1200c0c8c7bd 100644 --- a/services/tests/mockingservicestests/AndroidManifest.xml +++ b/services/tests/mockingservicestests/AndroidManifest.xml @@ -20,6 +20,7 @@ <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> <uses-permission android:name="android.permission.HARDWARE_TEST"/> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application android:testOnly="true" android:debuggable="true"> diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index 71661452d800..698e491a8926 100644 --- a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -25,14 +25,27 @@ import static android.app.AppOpsManager.OP_READ_SMS; import static android.app.AppOpsManager.OP_WIFI_SCAN; import static android.app.AppOpsManager.OP_WRITE_SMS; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; + import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; + import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; import android.content.Context; +import android.content.pm.PackageManagerInternal; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -43,12 +56,17 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; +import com.android.server.LocalServices; + +import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.quality.Strictness; import java.io.File; import java.util.List; @@ -69,21 +87,46 @@ public class AppOpsServiceTest { // State will be persisted into this XML file. private static final String APP_OPS_FILENAME = "appops-service-test.xml"; + private static final Context sContext = InstrumentationRegistry.getTargetContext(); + private static final String sMyPackageName = sContext.getOpPackageName(); + private File mAppOpsFile; - private Context mContext; private Handler mHandler; - private AppOpsManager mAppOpsManager; private AppOpsService mAppOpsService; - private String mMyPackageName; private int mMyUid; private long mTestStartMillis; + private StaticMockitoSession mMockingSession; + + @Before + public void mockPackageManagerInternalGetApplicationInfo() { + mMockingSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(LocalServices.class) + .startMocking(); + + // Mock LocalServices.getService(PackageManagerInternal.class).getApplicationInfo dependency + // needed by AppOpsService + PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class); + when(mockPackageManagerInternal.getApplicationInfo(eq(sMyPackageName), anyInt(), anyInt(), + anyInt())).thenReturn(sContext.getApplicationInfo()); + doReturn(mockPackageManagerInternal).when( + () -> LocalServices.getService(PackageManagerInternal.class)); + } + + private void setupAppOpsService() { + mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); + mAppOpsService.mContext = spy(sContext); + + // Always approve all permission checks + doNothing().when(mAppOpsService.mContext).enforcePermission(anyString(), anyInt(), + anyInt(), nullable(String.class)); + } private static String sDefaultAppopHistoryParameters; @Before public void setUp() { - mContext = InstrumentationRegistry.getTargetContext(); - mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME); + mAppOpsFile = new File(sContext.getFilesDir(), APP_OPS_FILENAME); if (mAppOpsFile.exists()) { // Start with a clean state (persisted into XML). mAppOpsFile.delete(); @@ -92,13 +135,10 @@ public class AppOpsServiceTest { HandlerThread handlerThread = new HandlerThread(TAG); handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); - mMyPackageName = mContext.getOpPackageName(); mMyUid = Process.myUid(); - mAppOpsManager = mContext.getSystemService(AppOpsManager.class); - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mHistoricalRegistry.systemReady(mContext.getContentResolver()); - mAppOpsService.mContext = mContext; + setupAppOpsService(); + mAppOpsService.mHistoricalRegistry.systemReady(sContext.getContentResolver()); mTestStartMillis = System.currentTimeMillis(); } @@ -118,6 +158,11 @@ public class AppOpsServiceTest { sDefaultAppopHistoryParameters); } + @After + public void resetStaticMocks() { + mMockingSession.finishMocking(); + } + @Test public void testGetOpsForPackage_noOpsLogged() { assertThat(getLoggedOps()).isNull(); @@ -125,16 +170,16 @@ public class AppOpsServiceTest { @Test public void testNoteOperationAndGetOpsForPackage() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED); // Note an op that's allowed. - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Note another op that's not allowed. - mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName); + mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName); loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED); @@ -148,17 +193,17 @@ public class AppOpsServiceTest { @Test public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() { // This op controls WIFI_SCAN - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED); - assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1, MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */); // Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well. - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ERRORED); - assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName)) + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED); + assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName)) .isEqualTo(MODE_ERRORED); assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis, @@ -168,15 +213,14 @@ public class AppOpsServiceTest { // Tests the dumping and restoring of the in-memory state to/from XML. @Test public void testStatePersistence() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); - mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); + mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName); mAppOpsService.writeState(); // Create a new app ops service, and initialize its state from XML. - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mContext = mContext; + setupAppOpsService(); mAppOpsService.readState(); // Query the state of the 2nd service. @@ -188,13 +232,12 @@ public class AppOpsServiceTest { // Tests that ops are persisted during shutdown. @Test public void testShutdown() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); mAppOpsService.shutdown(); // Create a new app ops service, and initialize its state from XML. - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mContext = mContext; + setupAppOpsService(); mAppOpsService.readState(); // Query the state of the 2nd service. @@ -204,21 +247,21 @@ public class AppOpsServiceTest { @Test public void testGetOpsForPackage() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); // Query all ops List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage( - mMyUid, mMyPackageName, null /* all ops */); + mMyUid, sMyPackageName, null /* all ops */); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Query specific ops loggedOps = mAppOpsService.getOpsForPackage( - mMyUid, mMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS}); + mMyUid, sMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS}); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Query unknown UID - loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, mMyPackageName, null /* all ops */); + loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, sMyPackageName, null /* all ops */); assertThat(loggedOps).isNull(); // Query unknown package name @@ -226,31 +269,31 @@ public class AppOpsServiceTest { assertThat(loggedOps).isNull(); // Query op code that's not been logged - loggedOps = mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, + loggedOps = mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, new int[]{OP_WRITE_SMS}); assertThat(loggedOps).isNull(); } @Test public void testPackageRemoved() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); - mAppOpsService.packageRemoved(mMyUid, mMyPackageName); + mAppOpsService.packageRemoved(mMyUid, sMyPackageName); assertThat(getLoggedOps()).isNull(); } @Ignore("Historical appops are disabled in Android Q") @Test public void testPackageRemovedHistoricalOps() throws InterruptedException { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000); - historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, mMyPackageName, + historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName, AppOpsManager.UID_STATE_PERSISTENT, 0, 1); mAppOpsService.addHistoricalOps(historicalOps); @@ -263,7 +306,7 @@ public class AppOpsServiceTest { }); // First, do a fetch to ensure it's written - mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0, + mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0, callback); latchRef.get().await(5, TimeUnit.SECONDS); @@ -271,11 +314,11 @@ public class AppOpsServiceTest { assertThat(resultOpsRef.get().isEmpty()).isFalse(); // Then, check it's deleted on removal - mAppOpsService.packageRemoved(mMyUid, mMyPackageName); + mAppOpsService.packageRemoved(mMyUid, sMyPackageName); latchRef.set(new CountDownLatch(1)); - mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0, + mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0, callback); latchRef.get().await(5, TimeUnit.SECONDS); @@ -285,8 +328,8 @@ public class AppOpsServiceTest { @Test public void testUidRemoved() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); @@ -297,7 +340,7 @@ public class AppOpsServiceTest { private void setupProcStateTests() { // For the location proc state tests - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_FOREGROUND); + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_FOREGROUND); mAppOpsService.mConstants.FG_SERVICE_STATE_SETTLE_TIME = 0; mAppOpsService.mConstants.TOP_STATE_SETTLE_TIME = 0; mAppOpsService.mConstants.BG_STATE_SETTLE_TIME = 0; @@ -308,18 +351,18 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -328,11 +371,11 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -341,12 +384,12 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); } @@ -355,18 +398,18 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -375,30 +418,30 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } private List<PackageOps> getLoggedOps() { - return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */); + return mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, null /* all ops */); } private void assertContainsOp(List<PackageOps> loggedOps, int opCode, long minMillis, @@ -407,7 +450,7 @@ public class AppOpsServiceTest { boolean opLogged = false; for (PackageOps pkgOps : loggedOps) { assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid()); - assertWithMessage("Unexpected package name").that(mMyPackageName).isEqualTo( + assertWithMessage("Unexpected package name").that(sMyPackageName).isEqualTo( pkgOps.getPackageName()); for (OpEntry opEntry : pkgOps.getOps()) { diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java index 19369dbe5f44..6c29f6050276 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java @@ -530,6 +530,46 @@ public class TimeControllerTest { } @Test + public void testJobDelayWakeupAlarmToggling() { + final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); + + JobStatus job = createJobStatus( + "testMaybeStartTrackingJobLocked_DeadlineReverseOrder", + createJob().setMinimumLatency(HOUR_IN_MILLIS)); + + doReturn(true).when(mTimeController) + .wouldBeReadyWithConstraintLocked(eq(job), anyInt()); + + // Starting off with using a wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; + InOrder inOrder = inOrder(mAlarmManager); + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), + eq(TAG_DELAY), any(), any(), any()); + + // Use a non wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = true; + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), eq(TAG_DELAY), + any(), any(), any()); + + // Back off, use a wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), + eq(TAG_DELAY), any(), any(), any()); + } + + @Test public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_AllReady() { mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.recheckAlarmsLocked(); diff --git a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java new file mode 100644 index 000000000000..968a402ff3b7 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 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 com.android.server; + +import static org.mockito.Mockito.*; + +import android.bluetooth.BluetoothAdapter; +import android.content.Context; +import android.os.Looper; +import android.provider.Settings; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.BluetoothAirplaneModeListener.AirplaneModeHelper; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class BluetoothAirplaneModeListenerTest { + private Context mContext; + private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; + private BluetoothAdapter mBluetoothAdapter; + private AirplaneModeHelper mHelper; + + @Mock BluetoothManagerService mBluetoothManagerService; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getTargetContext(); + + mHelper = mock(AirplaneModeHelper.class); + when(mHelper.getSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT)) + .thenReturn(BluetoothAirplaneModeListener.MAX_TOAST_COUNT); + doNothing().when(mHelper).setSettingsInt(anyString(), anyInt()); + doNothing().when(mHelper).showToastMessage(); + doNothing().when(mHelper).onAirplaneModeChanged(any(BluetoothManagerService.class)); + + mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener( + mBluetoothManagerService, Looper.getMainLooper(), mContext); + mBluetoothAirplaneModeListener.start(mHelper); + } + + @Test + public void testIgnoreOnAirplanModeChange() { + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + + when(mHelper.isBluetoothOn()).thenReturn(true); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + + when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true); + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + + when(mHelper.isAirplaneModeOn()).thenReturn(true); + Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange()); + } + + @Test + public void testHandleAirplaneModeChange_InvokeAirplaneModeChanged() { + mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + verify(mHelper).onAirplaneModeChanged(mBluetoothManagerService); + } + + @Test + public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_NotPopToast() { + mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT; + when(mHelper.isBluetoothOn()).thenReturn(true); + when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true); + when(mHelper.isAirplaneModeOn()).thenReturn(true); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + + verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, + BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); + verify(mHelper, times(0)).showToastMessage(); + verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService); + } + + @Test + public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_PopToast() { + mBluetoothAirplaneModeListener.mToastCount = 0; + when(mHelper.isBluetoothOn()).thenReturn(true); + when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true); + when(mHelper.isAirplaneModeOn()).thenReturn(true); + mBluetoothAirplaneModeListener.handleAirplaneModeChange(); + + verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON, + BluetoothManagerService.BLUETOOTH_ON_AIRPLANE); + verify(mHelper).showToastMessage(); + verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService); + } + + @Test + public void testIsPopToast_PopToast() { + mBluetoothAirplaneModeListener.mToastCount = 0; + Assert.assertTrue(mBluetoothAirplaneModeListener.shouldPopToast()); + verify(mHelper).setSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT, 1); + } + + @Test + public void testIsPopToast_NotPopToast() { + mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT; + Assert.assertFalse(mBluetoothAirplaneModeListener.shouldPopToast()); + verify(mHelper, times(0)).setSettingsInt(anyString(), anyInt()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java index 50437b4d5f3e..d367f71de921 100644 --- a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java @@ -36,7 +36,7 @@ public class DynamicSystemServiceTest extends AndroidTestCase { public void test1() { assertTrue("dynamic_system service available", mService != null); try { - mService.startInstallation(); + mService.startInstallation("dsu"); fail("DynamicSystemService did not throw SecurityException as expected"); } catch (SecurityException e) { // expected diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java index 8fd8d0461e75..ca5dfb133345 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java @@ -16,7 +16,7 @@ package com.android.server; -import static android.net.NetworkScoreManager.CACHE_FILTER_NONE; +import static android.net.NetworkScoreManager.SCORE_FILTER_NONE; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -29,6 +29,7 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; @@ -57,7 +58,6 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.net.wifi.WifiSsid; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -180,8 +180,8 @@ public class NetworkScoreServiceTest { } private ScanResult createScanResult(String ssid, String bssid) { - ScanResult result = new ScanResult(); - result.wifiSsid = WifiSsid.createFromAsciiEncoded(ssid); + ScanResult result = mock(ScanResult.class); + result.SSID = ssid; result.BSSID = bssid; return result; } @@ -304,7 +304,7 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mNetworkScoreCache, CACHE_FILTER_NONE); + mNetworkScoreCache, SCORE_FILTER_NONE); mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); @@ -319,9 +319,9 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mNetworkScoreCache, CACHE_FILTER_NONE); + mNetworkScoreCache, SCORE_FILTER_NONE); mNetworkScoreService.registerNetworkScoreCache( - NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE); + NetworkKey.TYPE_WIFI, mNetworkScoreCache2, SCORE_FILTER_NONE); // updateScores should update both caches mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); @@ -376,7 +376,7 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, - CACHE_FILTER_NONE); + SCORE_FILTER_NONE); mNetworkScoreService.clearScores(); verify(mNetworkScoreCache).clearScores(); @@ -390,7 +390,7 @@ public class NetworkScoreServiceTest { .thenReturn(PackageManager.PERMISSION_GRANTED); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, - CACHE_FILTER_NONE); + SCORE_FILTER_NONE); mNetworkScoreService.clearScores(); verify(mNetworkScoreCache).clearScores(); @@ -470,7 +470,7 @@ public class NetworkScoreServiceTest { try { mNetworkScoreService.registerNetworkScoreCache( - NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE); + NetworkKey.TYPE_WIFI, mNetworkScoreCache, SCORE_FILTER_NONE); fail("SecurityException expected"); } catch (SecurityException e) { // expected @@ -613,7 +613,7 @@ public class NetworkScoreServiceTest { new ArrayList<>(scoredNetworkList), NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE); verify(mNetworkScoreCache).updateScores(scoredNetworkList); verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter); @@ -654,7 +654,7 @@ public class NetworkScoreServiceTest { Collections.emptyList(), NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE); verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter); } @@ -671,7 +671,7 @@ public class NetworkScoreServiceTest { List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList); filteredList.remove(SCORED_NETWORK); when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK); verify(mNetworkScoreCache).updateScores(filteredList); verifyZeroInteractions(mScanResultsFilter); @@ -689,7 +689,7 @@ public class NetworkScoreServiceTest { List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList); filteredList.remove(SCORED_NETWORK); when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS); verify(mNetworkScoreCache).updateScores(filteredList); verifyZeroInteractions(mCurrentNetworkFilter); @@ -792,7 +792,7 @@ public class NetworkScoreServiceTest { @Test public void testScanResultsScoreCacheFilter_invalidScanResults() throws Exception { List<ScanResult> invalidScanResults = Lists.newArrayList( - new ScanResult(), + mock(ScanResult.class), createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid), createScanResult(WifiManager.UNKNOWN_SSID, SCORED_NETWORK.networkKey.wifiKey.bssid), createScanResult(SSID, null), diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java index f3c76b609c25..8871348d0027 100644 --- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManagerInternal; import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetManagerInternal; import android.appwidget.AppWidgetProviderInfo; import android.appwidget.PendingHostUpdate; import android.content.BroadcastReceiver; @@ -80,6 +81,7 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase { super.setUp(); LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); LocalServices.removeServiceForTest(ShortcutServiceInternal.class); + LocalServices.removeServiceForTest(AppWidgetManagerInternal.class); mTestContext = new TestContext(); mPkgName = mTestContext.getOpPackageName(); diff --git a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java new file mode 100644 index 000000000000..d0767ccb6f87 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java @@ -0,0 +1,58 @@ +/* + * 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 com.android.server.compat; + +import android.content.pm.ApplicationInfo; + +class ApplicationInfoBuilder { + private boolean mIsDebuggable; + private int mTargetSdk; + private String mPackageName; + + private ApplicationInfoBuilder() { + mTargetSdk = -1; + } + + static ApplicationInfoBuilder create() { + return new ApplicationInfoBuilder(); + } + + ApplicationInfoBuilder withTargetSdk(int targetSdk) { + mTargetSdk = targetSdk; + return this; + } + + ApplicationInfoBuilder debuggable() { + mIsDebuggable = true; + return this; + } + + ApplicationInfoBuilder withPackageName(String packageName) { + mPackageName = packageName; + return this; + } + + ApplicationInfo build() { + final ApplicationInfo applicationInfo = new ApplicationInfo(); + if (mIsDebuggable) { + applicationInfo.flags |= ApplicationInfo.FLAG_DEBUGGABLE; + } + applicationInfo.packageName = mPackageName; + applicationInfo.targetSdkVersion = mTargetSdk; + return applicationInfo; + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java new file mode 100644 index 000000000000..328c71dbc7db --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -0,0 +1,99 @@ +/* + * 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 com.android.server.compat; + +import android.content.Context; + +import com.android.internal.compat.AndroidBuildClassifier; + +import java.util.ArrayList; + +/** + * Helper class for creating a CompatConfig. + */ +class CompatConfigBuilder { + private ArrayList<CompatChange> mChanges; + private AndroidBuildClassifier mBuildClassifier; + private Context mContext; + + private CompatConfigBuilder(AndroidBuildClassifier buildClassifier, Context context) { + mChanges = new ArrayList<>(); + mBuildClassifier = buildClassifier; + mContext = context; + } + + static CompatConfigBuilder create(AndroidBuildClassifier buildClassifier, Context context) { + return new CompatConfigBuilder(buildClassifier, context); + } + + CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) { + mChanges.add(new CompatChange(id, "", sdk, false, "")); + return this; + } + + CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) { + mChanges.add(new CompatChange(id, "", sdk, true, "")); + return this; + } + + CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) { + mChanges.add(new CompatChange(id, name, sdk, false, "")); + return this; + } + + CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id, + String description) { + mChanges.add(new CompatChange(id, "", sdk, false, description)); + return this; + } + + CompatConfigBuilder addEnabledChangeWithId(long id) { + mChanges.add(new CompatChange(id, "", -1, false, "")); + return this; + } + + CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) { + mChanges.add(new CompatChange(id, name, -1, false, "")); + return this; + } + CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) { + mChanges.add(new CompatChange(id, "", -1, false, description)); + return this; + } + + CompatConfigBuilder addDisabledChangeWithId(long id) { + mChanges.add(new CompatChange(id, "", -1, true, "")); + return this; + } + + CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) { + mChanges.add(new CompatChange(id, name, -1, true, "")); + return this; + } + + CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) { + mChanges.add(new CompatChange(id, "", -1, true, description)); + return this; + } + + CompatConfig build() { + CompatConfig config = new CompatConfig(mBuildClassifier, mContext); + for (CompatChange change : mChanges) { + config.addChange(change); + } + return config; + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java index cb99c118a407..407f67e2fd8e 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -18,12 +18,25 @@ package com.android.server.compat; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertThrows; + +import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.compat.AndroidBuildClassifier; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.io.File; import java.io.FileOutputStream; @@ -34,12 +47,12 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) public class CompatConfigTest { - private ApplicationInfo makeAppInfo(String pName, int targetSdkVersion) { - ApplicationInfo ai = new ApplicationInfo(); - ai.packageName = pName; - ai.targetSdkVersion = targetSdkVersion; - return ai; - } + @Mock + private Context mContext; + @Mock + PackageManager mPackageManager; + @Mock + private AndroidBuildClassifier mBuildClassifier; private File createTempDir() { String base = System.getProperty("java.io.tmpdir"); @@ -54,112 +67,206 @@ public class CompatConfigTest { os.close(); } + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + // Assume userdebug/eng non-final build + when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); + when(mBuildClassifier.isFinalBuild()).thenReturn(false); + } + + @Test + public void testUnknownChangeEnabled() throws Exception { + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build())) + .isTrue(); + } + @Test - public void testUnknownChangeEnabled() { - CompatConfig pc = new CompatConfig(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue(); + public void testDisabledChangeDisabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .build(); + + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build())) + .isFalse(); } @Test - public void testDisabledChangeDisabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, "")); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse(); + public void testTargetSdkChangeDisabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addTargetSdkChangeWithId(2, 1234L) + .build(); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(2).build())) + .isFalse(); } @Test - public void testTargetSdkChangeDisabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, null)); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse(); + public void testTargetSdkChangeEnabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addTargetSdkChangeWithId(2, 1234L) + .build(); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue(); } @Test - public void testTargetSdkChangeEnabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, "")); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue(); + public void testDisabledOverrideTargetSdkChange() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addTargetSdkDisabledChangeWithId(2, 1234L) + .build(); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isFalse(); } @Test - public void testDisabledOverrideTargetSdkChange() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null)); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse(); + public void testGetDisabledChanges() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .addEnabledChangeWithId(2345L) + .build(); + + assertThat(compatConfig.getDisabledChanges( + ApplicationInfoBuilder.create().build())).asList().containsExactly(1234L); } @Test - public void testGetDisabledChanges() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); - pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false, null)); - assertThat(pc.getDisabledChanges( - makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L); + public void testGetDisabledChangesSorted() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .addDisabledChangeWithId(123L) + .addDisabledChangeWithId(12L) + .build(); + + assertThat(compatConfig.getDisabledChanges(ApplicationInfoBuilder.create().build())) + .asList().containsExactly(12L, 123L, 1234L); } @Test - public void testGetDisabledChangesSorted() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null)); - pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true, null)); - pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true, null)); - assertThat(pc.getDisabledChanges( - makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L); + public void testPackageOverrideEnabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .build(); + + compatConfig.addOverride(1234L, "com.some.package", true); + + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.some.package").build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.other.package").build())).isFalse(); } @Test - public void testPackageOverrideEnabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); // disabled - pc.addOverride(1234L, "com.some.package", true); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse(); + public void testPackageOverrideDisabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addEnabledChangeWithId(1234L) + .build(); + + compatConfig.addOverride(1234L, "com.some.package", false); + + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.some.package").build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.other.package").build())).isTrue(); } @Test - public void testPackageOverrideDisabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null)); - pc.addOverride(1234L, "com.some.package", false); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue(); + public void testPackageOverrideUnknownPackage() throws Exception { + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + + compatConfig.addOverride(1234L, "com.some.package", false); + + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.some.package").build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.other.package").build())).isTrue(); } @Test - public void testPackageOverrideUnknownPackage() { - CompatConfig pc = new CompatConfig(); - pc.addOverride(1234L, "com.some.package", false); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue(); + public void testPreventAddOverride() throws Exception { + final long changeId = 1234L; + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + PackageManager packageManager = mock(PackageManager.class); + when(mContext.getPackageManager()).thenReturn(packageManager); + when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + // Force the validator to prevent overriding the change by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + assertThrows(SecurityException.class, + () -> compatConfig.addOverride(1234L, "com.some.package", true) + ); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse(); } @Test - public void testPackageOverrideUnknownChange() { - CompatConfig pc = new CompatConfig(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue(); + public void testPreventRemoveOverride() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + // Assume the override was allowed to be added. + compatConfig.addOverride(1234L, "com.some.package", true); + + // Validator allows turning on the change. + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); + + // Reject all override attempts. + // Force the validator to prevent overriding the change by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + // Try to turn off change, but validator prevents it. + assertThrows(SecurityException.class, + () -> compatConfig.removeOverride(1234L, "com.some.package")); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); } @Test - public void testRemovePackageOverride() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null)); - pc.addOverride(1234L, "com.some.package", false); - pc.removeOverride(1234L, "com.some.package"); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue(); + public void testRemovePackageOverride() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addEnabledChangeWithId(1234L) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + + assertThat(compatConfig.addOverride(1234L, "com.some.package", false)).isTrue(); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse(); + + compatConfig.removeOverride(1234L, "com.some.package"); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); } @Test - public void testLookupChangeId() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null)); - pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false, null)); - assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L); + public void testLookupChangeId() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addEnabledChangeWithIdAndName(1234L, "MY_CHANGE") + .addEnabledChangeWithIdAndName(2345L, "MY_OTHER_CHANGE") + .build(); + + assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(1234L); } @Test - public void testLookupChangeIdNotPresent() { - CompatConfig pc = new CompatConfig(); - assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L); + public void testLookupChangeIdNotPresent() throws Exception { + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(-1L); } @Test @@ -172,14 +279,17 @@ public class CompatConfigTest { File dir = createTempDir(); writeToFile(dir, "platform_compat_config.xml", configXml); - - CompatConfig pc = new CompatConfig(); - pc.initConfigFromLib(dir); - - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue(); - assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse(); - assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue(); + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + compatConfig.initConfigFromLib(dir); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1235L, + ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1236L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue(); } @Test @@ -195,15 +305,16 @@ public class CompatConfigTest { File dir = createTempDir(); writeToFile(dir, "libcore_platform_compat_config.xml", configXml1); writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2); - - CompatConfig pc = new CompatConfig(); - pc.initConfigFromLib(dir); - - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue(); - assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse(); - assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue(); + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + compatConfig.initConfigFromLib(dir); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1235L, + ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1236L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue(); } } - - diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java new file mode 100644 index 000000000000..793296e88169 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java @@ -0,0 +1,52 @@ +/* + * 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 com.android.server.compat; + +import android.compat.Compatibility; + +import com.android.internal.compat.CompatibilityChangeConfig; + +import java.util.HashSet; +import java.util.Set; + +class CompatibilityChangeConfigBuilder { + private Set<Long> mEnabled; + private Set<Long> mDisabled; + + private CompatibilityChangeConfigBuilder() { + mEnabled = new HashSet<>(); + mDisabled = new HashSet<>(); + } + + static CompatibilityChangeConfigBuilder create() { + return new CompatibilityChangeConfigBuilder(); + } + + CompatibilityChangeConfigBuilder enable(Long id) { + mEnabled.add(id); + return this; + } + + CompatibilityChangeConfigBuilder disable(Long id) { + mDisabled.add(id); + return this; + } + + CompatibilityChangeConfig build() { + return new CompatibilityChangeConfig(new Compatibility.ChangeConfig(mEnabled, mDisabled)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java new file mode 100644 index 000000000000..b14291b34195 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java @@ -0,0 +1,383 @@ +/* + * 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 com.android.server.compat; + +import static com.android.internal.compat.OverrideAllowedState.ALLOWED; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.PackageManager; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.compat.AndroidBuildClassifier; +import com.android.internal.compat.IOverrideValidator; +import com.android.internal.compat.OverrideAllowedState; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +public class OverrideValidatorImplTest { + private static final String PACKAGE_NAME = "my.package"; + private static final int TARGET_SDK = 10; + private static final int TARGET_SDK_BEFORE = 9; + private static final int TARGET_SDK_AFTER = 11; + + @Mock + private PackageManager mPackageManager; + @Mock + Context mContext; + + private AndroidBuildClassifier debuggableBuild() { + AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); + when(buildClassifier.isDebuggableBuild()).thenReturn(true); + return buildClassifier; + } + + private AndroidBuildClassifier betaBuild() { + AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); + when(buildClassifier.isDebuggableBuild()).thenReturn(false); + when(buildClassifier.isFinalBuild()).thenReturn(false); + return buildClassifier; + } + + private AndroidBuildClassifier finalBuild() { + AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); + when(buildClassifier.isDebuggableBuild()).thenReturn(false); + when(buildClassifier.isFinalBuild()).thenReturn(true); + return buildClassifier; + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + } + + @Test + public void getOverrideAllowedState_debugBuildAnyChangeDebugApp_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3) + .addEnabledChangeWithId(4) + .addDisabledChangeWithId(5).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .debuggable() + .withTargetSdk(TARGET_SDK) + .withPackageName(PACKAGE_NAME).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + OverrideAllowedState stateEnabledChange = + overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME); + OverrideAllowedState stateDisabledChange = + overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateEnabledChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateDisabledChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + } + + @Test + public void getOverrideAllowedState_debugBuildAnyChangeReleaseApp_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3) + .addEnabledChangeWithId(4) + .addDisabledChangeWithId(5).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .withTargetSdk(TARGET_SDK).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + OverrideAllowedState stateEnabledChange = + overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME); + OverrideAllowedState stateDisabledChange = + overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateEnabledChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateDisabledChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + } + + @Test + public void getOverrideAllowedState_betaBuildTargetSdkChangeDebugApp_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .debuggable() + .withTargetSdk(TARGET_SDK) + .withPackageName(PACKAGE_NAME).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_BEFORE)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER)); + } + + @Test + public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) + .addEnabledChangeWithId(1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .debuggable() + .build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + } + + @Test + public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) + .addDisabledChangeWithId(1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .debuggable() + .withPackageName(PACKAGE_NAME).build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + } + + @Test + public void getOverrideAllowedState_betaBuildAnyChangeReleaseApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3) + .addEnabledChangeWithId(4) + .addDisabledChangeWithId(5).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .withTargetSdk(TARGET_SDK).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + OverrideAllowedState stateEnabledChange = + overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME); + OverrideAllowedState stateDisabledChange = + overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateEnabledChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateDisabledChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + } + + @Test + public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptin_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .debuggable() + .withTargetSdk(TARGET_SDK) + .withPackageName(PACKAGE_NAME).build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER)); + } + + @Test + public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptout_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .withTargetSdk(TARGET_SDK) + .debuggable() + .build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange).isEqualTo( + new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, + TARGET_SDK_BEFORE)); + assertThat(stateTargetSdkEqualChange).isEqualTo( + new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, TARGET_SDK)); + } + + @Test + public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addEnabledChangeWithId(1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .debuggable().build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1)); + } + + @Test + public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addDisabledChangeWithId(1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .debuggable().build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1)); + } + + @Test + public void getOverrideAllowedState_finalBuildAnyChangeReleaseApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3) + .addEnabledChangeWithId(4) + .addDisabledChangeWithId(5).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .withTargetSdk(TARGET_SDK).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + OverrideAllowedState stateEnabledChange = + overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME); + OverrideAllowedState stateDisabledChange = + overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateEnabledChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateDisabledChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index c406876c5cee..ce5d6d9be770 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -26,21 +26,20 @@ import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.times; import static org.testng.Assert.assertThrows; -import android.compat.Compatibility; import android.content.Context; import android.content.pm.PackageManager; -import com.android.internal.compat.CompatibilityChangeConfig; +import androidx.test.runner.AndroidJUnit4; -import com.google.common.collect.ImmutableSet; +import com.android.internal.compat.AndroidBuildClassifier; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; -@RunWith(MockitoJUnitRunner.class) +@RunWith(AndroidJUnit4.class) public class PlatformCompatTest { private static final String PACKAGE_NAME = "my.package"; @@ -50,84 +49,77 @@ public class PlatformCompatTest { private PackageManager mPackageManager; @Mock CompatChange.ChangeListener mListener1, mListener2; - + PlatformCompat mPlatformCompat; + CompatConfig mCompatConfig; + @Mock + private AndroidBuildClassifier mBuildClassifier; @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow( new PackageManager.NameNotFoundException()); - CompatConfig.get().clearChanges(); + mCompatConfig = new CompatConfig(mBuildClassifier, mContext); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + // Assume userdebug/eng non-final build + when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); + when(mBuildClassifier.isFinalBuild()).thenReturn(false); } @Test - public void testRegisterListenerToSameIdThrows() { - PlatformCompat pc = new PlatformCompat(mContext); - + public void testRegisterListenerToSameIdThrows() throws Exception { // Registering a listener to change 1 is successful. - pc.registerListener(1, mListener1); + mPlatformCompat.registerListener(1, mListener1); // Registering a listener to change 2 is successful. - pc.registerListener(2, mListener1); + mPlatformCompat.registerListener(2, mListener1); // Trying to register another listener to change id 1 fails. - assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1)); + assertThrows(IllegalStateException.class, + () -> mPlatformCompat.registerListener(1, mListener1)); } @Test - public void testRegisterListenerReturn() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())), + public void testRegisterListenerReturn() throws Exception { + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).build(), PACKAGE_NAME); // Change id 1 is known (added in setOverrides). - assertThat(pc.registerListener(1, mListener1)).isTrue(); + assertThat(mPlatformCompat.registerListener(1, mListener1)).isTrue(); // Change 2 is unknown. - assertThat(pc.registerListener(2, mListener1)).isFalse(); + assertThat(mPlatformCompat.registerListener(2, mListener1)).isFalse(); } @Test - public void testListenerCalledOnSetOverrides() { - PlatformCompat pc = new PlatformCompat(mContext); + public void testListenerCalledOnSetOverrides() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener1); - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener1); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerNotCalledOnWrongPackage() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener1); + public void testListenerNotCalledOnWrongPackage() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener1); - pc.setOverridesForTest( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, never()).onCompatChange("other.package"); } @Test - public void testListenerCalledOnSetOverridesTwoListeners() { - PlatformCompat pc = new PlatformCompat(mContext); - pc.registerListener(1, mListener1); + public void testListenerCalledOnSetOverridesTwoListeners() throws Exception { + mPlatformCompat.registerListener(1, mListener1); - final ImmutableSet<Long> enabled = ImmutableSet.of(1L); - final ImmutableSet<Long> disabled = ImmutableSet.of(2L); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); @@ -136,11 +128,10 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.registerListener(2, mListener2); + mPlatformCompat.registerListener(2, mListener2); - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); @@ -148,31 +139,23 @@ public class PlatformCompatTest { } @Test - public void testListenerCalledOnSetOverridesForTest() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener1); + public void testListenerCalledOnSetOverridesForTest() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener1); - pc.setOverridesForTest( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerCalledOnSetOverridesTwoListenersForTest() { - PlatformCompat pc = new PlatformCompat(mContext); - pc.registerListener(1, mListener1); + public void testListenerCalledOnSetOverridesTwoListenersForTest() throws Exception { + mPlatformCompat.registerListener(1, mListener1); - final ImmutableSet<Long> enabled = ImmutableSet.of(1L); - final ImmutableSet<Long> disabled = ImmutableSet.of(2L); - - pc.setOverridesForTest( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); @@ -181,10 +164,10 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.registerListener(2, mListener2); - pc.setOverridesForTest( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)), + mPlatformCompat.registerListener(2, mListener2); + + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); @@ -192,15 +175,12 @@ public class PlatformCompatTest { } @Test - public void testListenerCalledOnClearOverrides() { - PlatformCompat pc = new PlatformCompat(mContext); + public void testListenerCalledOnClearOverrides() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener2); - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener2); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, never()).onCompatChange(PACKAGE_NAME); @@ -208,21 +188,18 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.clearOverrides(PACKAGE_NAME); + mPlatformCompat.clearOverrides(PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, never()).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerCalledOnClearOverridesMultipleOverrides() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener2); + public void testListenerCalledOnClearOverridesMultipleOverrides() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener2); - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME); @@ -230,21 +207,18 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.clearOverrides(PACKAGE_NAME); + mPlatformCompat.clearOverrides(PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerCalledOnClearOverrideExists() { - PlatformCompat pc = new PlatformCompat(mContext); + public void testListenerCalledOnClearOverrideExists() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener2); - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener2); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, never()).onCompatChange(PACKAGE_NAME); @@ -252,21 +226,17 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.clearOverride(1, PACKAGE_NAME); + mPlatformCompat.clearOverride(1, PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, never()).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerCalledOnClearOverrideDoesntExist() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.registerListener(1, mListener1); + public void testListenerCalledOnClearOverrideDoesntExist() throws Exception { + mPlatformCompat.registerListener(1, mListener1); - pc.clearOverride(1, PACKAGE_NAME); + mPlatformCompat.clearOverride(1, PACKAGE_NAME); // Listener not called when a non existing override is removed. verify(mListener1, never()).onCompatChange(PACKAGE_NAME); } - - } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 1a67576c218f..960f670904d6 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -217,6 +217,8 @@ public class DpmMockContext extends MockContext { return mMockSystemServices.wifiManager; case Context.ACCOUNT_SERVICE: return mMockSystemServices.accountManager; + case Context.TELEPHONY_SERVICE: + return mMockSystemServices.telephonyManager; } throw new UnsupportedOperationException(); } diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 7e08d955c5d1..2e58ad68fc7c 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -37,6 +37,7 @@ import static android.net.NetworkPolicyManager.uidRulesToString; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_ALL; +import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.MB_IN_BYTES; @@ -111,7 +112,7 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; -import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.os.Binder; import android.os.Handler; import android.os.INetworkManagementService; @@ -1197,11 +1198,11 @@ public class NetworkPolicyManagerServiceTest { history.recordData(start, end, new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0)); stats.clear(); - stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); - stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); - stats.addValues(IFACE_ALL, UID_C, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_C, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); reset(mNotifManager); @@ -1225,9 +1226,9 @@ public class NetworkPolicyManagerServiceTest { history.recordData(start, end, new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0)); stats.clear(); - stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(960), 0, 0, 0, 0); - stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); reset(mNotifManager); @@ -1683,6 +1684,59 @@ public class NetworkPolicyManagerServiceTest { } /** + * Test that when StatsProvider triggers limit reached, new limit will be calculated and + * re-armed. + */ + @Test + public void testStatsProviderLimitReached() throws Exception { + final int CYCLE_DAY = 15; + + final NetworkStats stats = new NetworkStats(0L, 1); + stats.addEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE, + 2999, 1, 2000, 1, 0); + when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong())) + .thenReturn(stats.getTotalBytes()); + when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong())) + .thenReturn(stats); + + // Get active mobile network in place + expectMobileDefaults(); + mService.updateNetworks(); + verify(mStatsService).setStatsProviderLimit(TEST_IFACE, Long.MAX_VALUE); + + // Set limit to 10KB. + setNetworkPolicies(new NetworkPolicy( + sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, 10000L, + true)); + postMsgAndWaitForCompletion(); + + // Verifies that remaining quota is set to providers. + verify(mStatsService).setStatsProviderLimit(TEST_IFACE, 10000L - 4999L); + + reset(mStatsService); + + // Increase the usage. + stats.addEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE, + 1000, 1, 999, 1, 0); + when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong())) + .thenReturn(stats.getTotalBytes()); + when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong())) + .thenReturn(stats); + + // Simulates that limit reached fires earlier by provider, but actually the quota is not + // yet reached. + final NetworkPolicyManagerInternal npmi = LocalServices + .getService(NetworkPolicyManagerInternal.class); + npmi.onStatsProviderLimitReached("TEST"); + + // Verifies that the limit reached leads to a force update and new limit should be set. + postMsgAndWaitForCompletion(); + verify(mStatsService).forceUpdate(); + postMsgAndWaitForCompletion(); + verify(mStatsService).setStatsProviderLimit(TEST_IFACE, 10000L - 4999L - 1999L); + } + + /** * Exhaustively test isUidNetworkingBlocked to output the expected results based on external * conditions. */ @@ -1784,7 +1838,8 @@ public class NetworkPolicyManagerServiceTest { if (!roaming) { nc.addCapability(NET_CAPABILITY_NOT_ROAMING); } - nc.setNetworkSpecifier(new StringNetworkSpecifier(String.valueOf(subId))); + nc.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(subId).build()); return nc; } diff --git a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java index bd3d9ab2220d..3852b9fec001 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.content.Context; import android.content.pm.ModuleInfo; +import android.content.pm.PackageManager; import android.test.InstrumentationTestCase; import com.android.frameworks.servicestests.R; @@ -28,7 +29,7 @@ public class ModuleInfoProviderTest extends InstrumentationTestCase { public void testSuccessfulParse() { ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata); - List<ModuleInfo> mi = provider.getInstalledModules(0); + List<ModuleInfo> mi = provider.getInstalledModules(PackageManager.MATCH_ALL); assertEquals(2, mi.size()); Collections.sort(mi, (ModuleInfo m1, ModuleInfo m2) -> @@ -49,18 +50,18 @@ public class ModuleInfoProviderTest extends InstrumentationTestCase { public void testParseFailure_incorrectTopLevelElement() { ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata1); - assertEquals(0, provider.getInstalledModules(0).size()); + assertEquals(0, provider.getInstalledModules(PackageManager.MATCH_ALL).size()); } public void testParseFailure_incorrectModuleElement() { ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata2); - assertEquals(0, provider.getInstalledModules(0).size()); + assertEquals(0, provider.getInstalledModules(PackageManager.MATCH_ALL).size()); } public void testParse_unknownAttributesIgnored() { ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata); - List<ModuleInfo> mi = provider.getInstalledModules(0); + List<ModuleInfo> mi = provider.getInstalledModules(PackageManager.MATCH_ALL); assertEquals(2, mi.size()); ModuleInfo mi1 = provider.getModuleInfo("com.android.module1", 0); diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index 0196279cbf56..a4ba056b96a8 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -160,6 +160,31 @@ public class DexManagerTests { } @Test + public void testNotifyPrimaryAndSecondary() { + List<String> dexFiles = mFooUser0.getBaseAndSplitDexPaths(); + List<String> secondaries = mFooUser0.getSecondaryDexPaths(); + int baseAndSplitCount = dexFiles.size(); + dexFiles.addAll(secondaries); + + notifyDexLoad(mFooUser0, dexFiles, mUser0); + + PackageUseInfo pui = getPackageUseInfo(mFooUser0); + assertIsUsedByOtherApps(mFooUser0, pui, false); + assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); + + String[] allExpectedContexts = DexoptUtils.processContextForDexLoad( + Arrays.asList(mFooUser0.mClassLoader), + Arrays.asList(String.join(File.pathSeparator, dexFiles))); + String[] secondaryExpectedContexts = Arrays.copyOfRange(allExpectedContexts, + baseAndSplitCount, dexFiles.size()); + + assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0, + secondaryExpectedContexts); + + assertHasDclInfo(mFooUser0, mFooUser0, secondaries); + } + + @Test public void testNotifySecondaryForeign() { // Foo loads bar secondary files. List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java index 72a7f508772b..ae5369204428 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java @@ -18,15 +18,18 @@ package com.android.server.timedetector; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.NetworkTimeSuggestion; import android.app.timedetector.PhoneTimeSuggestion; import android.content.Context; import android.content.pm.PackageManager; @@ -34,7 +37,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; -import android.util.TimestampedValue; +import android.os.TimestampedValue; import androidx.test.runner.AndroidJUnit4; @@ -77,6 +80,22 @@ public class TimeDetectorServiceTest { mHandlerThread.join(); } + @Test(expected = SecurityException.class) + public void testSuggestPhoneTime_withoutPermission() { + doThrow(new SecurityException("Mock")) + .when(mMockContext).enforceCallingPermission(anyString(), any()); + PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion(); + + try { + mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion); + fail(); + } finally { + verify(mMockContext).enforceCallingPermission( + eq(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE), + anyString()); + } + } + @Test public void testSuggestPhoneTime() throws Exception { doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); @@ -86,13 +105,29 @@ public class TimeDetectorServiceTest { mTestHandler.assertTotalMessagesEnqueued(1); verify(mMockContext).enforceCallingPermission( - eq(android.Manifest.permission.SET_TIME), + eq(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE), anyString()); mTestHandler.waitForEmptyQueue(); mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion); } + @Test(expected = SecurityException.class) + public void testSuggestManualTime_withoutPermission() { + doThrow(new SecurityException("Mock")) + .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); + ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(); + + try { + mTimeDetectorService.suggestManualTime(manualTimeSuggestion); + fail(); + } finally { + verify(mMockContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE), + anyString()); + } + } + @Test public void testSuggestManualTime() throws Exception { doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); @@ -102,13 +137,43 @@ public class TimeDetectorServiceTest { mTestHandler.assertTotalMessagesEnqueued(1); verify(mMockContext).enforceCallingOrSelfPermission( - eq(android.Manifest.permission.SET_TIME), + eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE), anyString()); mTestHandler.waitForEmptyQueue(); mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion); } + @Test(expected = SecurityException.class) + public void testSuggestNetworkTime_withoutPermission() { + doThrow(new SecurityException("Mock")) + .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); + NetworkTimeSuggestion NetworkTimeSuggestion = createNetworkTimeSuggestion(); + + try { + mTimeDetectorService.suggestNetworkTime(NetworkTimeSuggestion); + fail(); + } finally { + verify(mMockContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.SET_TIME), anyString()); + } + } + + @Test + public void testSuggestNetworkTime() throws Exception { + doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); + + NetworkTimeSuggestion NetworkTimeSuggestion = createNetworkTimeSuggestion(); + mTimeDetectorService.suggestNetworkTime(NetworkTimeSuggestion); + mTestHandler.assertTotalMessagesEnqueued(1); + + verify(mMockContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.SET_TIME), anyString()); + + mTestHandler.waitForEmptyQueue(); + mStubbedTimeDetectorStrategy.verifySuggestNetworkTimeCalled(NetworkTimeSuggestion); + } + @Test public void testDump() { when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)) @@ -146,11 +211,17 @@ public class TimeDetectorServiceTest { return new ManualTimeSuggestion(timeValue); } + private static NetworkTimeSuggestion createNetworkTimeSuggestion() { + TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L); + return new NetworkTimeSuggestion(timeValue); + } + private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy { // Call tracking. private PhoneTimeSuggestion mLastPhoneSuggestion; private ManualTimeSuggestion mLastManualSuggestion; + private NetworkTimeSuggestion mLastNetworkSuggestion; private boolean mLastAutoTimeDetectionToggleCalled; private boolean mDumpCalled; @@ -171,6 +242,12 @@ public class TimeDetectorServiceTest { } @Override + public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) { + resetCallTracking(); + mLastNetworkSuggestion = timeSuggestion; + } + + @Override public void handleAutoTimeDetectionChanged() { resetCallTracking(); mLastAutoTimeDetectionToggleCalled = true; @@ -185,6 +262,7 @@ public class TimeDetectorServiceTest { void resetCallTracking() { mLastPhoneSuggestion = null; mLastManualSuggestion = null; + mLastNetworkSuggestion = null; mLastAutoTimeDetectionToggleCalled = false; mDumpCalled = false; } @@ -197,6 +275,10 @@ public class TimeDetectorServiceTest { assertEquals(expectedSuggestion, mLastManualSuggestion); } + public void verifySuggestNetworkTimeCalled(NetworkTimeSuggestion expectedSuggestion) { + assertEquals(expectedSuggestion, mLastNetworkSuggestion); + } + void verifyHandleAutoTimeDetectionToggleCalled() { assertTrue(mLastAutoTimeDetectionToggleCalled); } diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java index 1aa3d8fe654b..d940a6a320f2 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java @@ -18,18 +18,17 @@ package com.android.server.timedetector; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.NetworkTimeSuggestion; import android.app.timedetector.PhoneTimeSuggestion; -import android.content.Intent; import android.icu.util.Calendar; import android.icu.util.GregorianCalendar; import android.icu.util.TimeZone; -import android.util.TimestampedValue; +import android.os.TimestampedValue; import androidx.test.runner.AndroidJUnit4; @@ -45,14 +44,16 @@ public class TimeDetectorStrategyImplTest { private static final TimestampedValue<Long> ARBITRARY_CLOCK_INITIALIZATION_INFO = new TimestampedValue<>( 123456789L /* realtimeClockMillis */, - createUtcTime(1977, 1, 1, 12, 0, 0)); + createUtcTime(2008, 5, 23, 12, 0, 0)); + /** + * An arbitrary time, very different from the {@link #ARBITRARY_CLOCK_INITIALIZATION_INFO} + * time. Can be used as the basis for time suggestions. + */ private static final long ARBITRARY_TEST_TIME_MILLIS = createUtcTime(2018, 1, 1, 12, 0, 0); private static final int ARBITRARY_PHONE_ID = 123456; - private static final long ONE_DAY_MILLIS = Duration.ofDays(1).toMillis(); - private Script mScript; @Before @@ -67,15 +68,15 @@ public class TimeDetectorStrategyImplTest { int phoneId = ARBITRARY_PHONE_ID; long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; + PhoneTimeSuggestion timeSuggestion = mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); - int clockIncrement = 1000; - long expectedSystemClockMillis = testTimeMillis + clockIncrement; + mScript.simulateTimePassing() + .simulatePhoneTimeSuggestion(timeSuggestion); - mScript.simulateTimePassing(clockIncrement) - .simulatePhoneTimeSuggestion(timeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis, true /* expectNetworkBroadcast */) + long expectedSystemClockMillis = + mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime()); + mScript.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis) .assertLatestPhoneSuggestion(phoneId, timeSuggestion); } @@ -94,30 +95,27 @@ public class TimeDetectorStrategyImplTest { @Test public void testSuggestPhoneTime_systemClockThreshold() { - int systemClockUpdateThresholdMillis = 1000; + final int systemClockUpdateThresholdMillis = 1000; + final int clockIncrementMillis = 100; mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) .pokeThresholds(systemClockUpdateThresholdMillis) .pokeAutoTimeDetectionEnabled(true); - final int clockIncrement = 100; int phoneId = ARBITRARY_PHONE_ID; // Send the first time signal. It should be used. { - long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; PhoneTimeSuggestion timeSuggestion1 = - mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); - TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); + mScript.generatePhoneTimeSuggestion(phoneId, ARBITRARY_TEST_TIME_MILLIS); // Increment the the device clocks to simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); + mScript.simulateTimePassing(clockIncrementMillis); long expectedSystemClockMillis1 = - TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); + mScript.calculateTimeInMillisForNow(timeSuggestion1.getUtcTime()); mScript.simulatePhoneTimeSuggestion(timeSuggestion1) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis1, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1) .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); } @@ -127,7 +125,7 @@ public class TimeDetectorStrategyImplTest { int underThresholdMillis = systemClockUpdateThresholdMillis - 1; PhoneTimeSuggestion timeSuggestion2 = mScript.generatePhoneTimeSuggestion( phoneId, mScript.peekSystemClockMillis() + underThresholdMillis); - mScript.simulateTimePassing(clockIncrement) + mScript.simulateTimePassing(clockIncrementMillis) .simulatePhoneTimeSuggestion(timeSuggestion2) .verifySystemClockWasNotSetAndResetCallTracking() .assertLatestPhoneSuggestion(phoneId, timeSuggestion2); @@ -138,15 +136,13 @@ public class TimeDetectorStrategyImplTest { PhoneTimeSuggestion timeSuggestion3 = mScript.generatePhoneTimeSuggestion( phoneId, mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis); - mScript.simulateTimePassing(clockIncrement); + mScript.simulateTimePassing(clockIncrementMillis); long expectedSystemClockMillis3 = - TimeDetectorStrategy.getTimeAt(timeSuggestion3.getUtcTime(), - mScript.peekElapsedRealtimeMillis()); + mScript.calculateTimeInMillisForNow(timeSuggestion3.getUtcTime()); mScript.simulatePhoneTimeSuggestion(timeSuggestion3) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis3, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis3) .assertLatestPhoneSuggestion(phoneId, timeSuggestion3); } } @@ -162,50 +158,48 @@ public class TimeDetectorStrategyImplTest { int phone1Id = ARBITRARY_PHONE_ID; int phone2Id = ARBITRARY_PHONE_ID + 1; long phone1TimeMillis = ARBITRARY_TEST_TIME_MILLIS; - long phone2TimeMillis = phone1TimeMillis + 60000; - - final int clockIncrement = 999; + long phone2TimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(1).toMillis(); // Make a suggestion with phone2Id. { PhoneTimeSuggestion phone2TimeSuggestion = mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis); - mScript.simulateTimePassing(clockIncrement); + mScript.simulateTimePassing(); - long expectedSystemClockMillis = phone2TimeMillis + clockIncrement; + long expectedSystemClockMillis = + mScript.calculateTimeInMillisForNow(phone2TimeSuggestion.getUtcTime()); mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis) .assertLatestPhoneSuggestion(phone1Id, null) .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion); } - mScript.simulateTimePassing(clockIncrement); + mScript.simulateTimePassing(); // Now make a different suggestion with phone1Id. { PhoneTimeSuggestion phone1TimeSuggestion = mScript.generatePhoneTimeSuggestion(phone1Id, phone1TimeMillis); - mScript.simulateTimePassing(clockIncrement); + mScript.simulateTimePassing(); - long expectedSystemClockMillis = phone1TimeMillis + clockIncrement; + long expectedSystemClockMillis = + mScript.calculateTimeInMillisForNow(phone1TimeSuggestion.getUtcTime()); mScript.simulatePhoneTimeSuggestion(phone1TimeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis) .assertLatestPhoneSuggestion(phone1Id, phone1TimeSuggestion); } - mScript.simulateTimePassing(clockIncrement); + mScript.simulateTimePassing(); // Make another suggestion with phone2Id. It should be stored but not used because the // phone1Id suggestion will still "win". { PhoneTimeSuggestion phone2TimeSuggestion = mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis); - mScript.simulateTimePassing(clockIncrement); + mScript.simulateTimePassing(); mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion) .verifySystemClockWasNotSetAndResetCallTracking() @@ -220,13 +214,13 @@ public class TimeDetectorStrategyImplTest { { PhoneTimeSuggestion phone2TimeSuggestion = mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis); - mScript.simulateTimePassing(clockIncrement); + mScript.simulateTimePassing(); - long expectedSystemClockMillis = phone2TimeMillis + clockIncrement; + long expectedSystemClockMillis = + mScript.calculateTimeInMillisForNow(phone2TimeSuggestion.getUtcTime()); mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis) .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion); } } @@ -239,7 +233,7 @@ public class TimeDetectorStrategyImplTest { int phoneId = ARBITRARY_PHONE_ID; PhoneTimeSuggestion timeSuggestion = mScript.generatePhoneTimeSuggestion(phoneId, ARBITRARY_TEST_TIME_MILLIS); - mScript.simulateTimePassing(1000) + mScript.simulateTimePassing() .simulatePhoneTimeSuggestion(timeSuggestion) .verifySystemClockWasNotSetAndResetCallTracking() .assertLatestPhoneSuggestion(phoneId, timeSuggestion); @@ -260,12 +254,10 @@ public class TimeDetectorStrategyImplTest { TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); // Initialize the strategy / device with a time set from a phone suggestion. - mScript.simulateTimePassing(100); - long expectedSystemClockMillis1 = - TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); + mScript.simulateTimePassing(); + long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(utcTime1); mScript.simulatePhoneTimeSuggestion(timeSuggestion1) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis1, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1) .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); // The UTC time increment should be larger than the system clock update threshold so we @@ -299,13 +291,11 @@ public class TimeDetectorStrategyImplTest { long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100; TimestampedValue<Long> utcTime4 = new TimestampedValue<>( validReferenceTimeMillis, validUtcTimeMillis); - long expectedSystemClockMillis4 = - TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis()); + long expectedSystemClockMillis4 = mScript.calculateTimeInMillisForNow(utcTime4); PhoneTimeSuggestion timeSuggestion4 = createPhoneTimeSuggestion(phoneId, utcTime4); mScript.simulatePhoneTimeSuggestion(timeSuggestion4) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis4, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4) .assertLatestPhoneSuggestion(phoneId, timeSuggestion4); } @@ -335,13 +325,11 @@ public class TimeDetectorStrategyImplTest { // Simulate more time passing. mScript.simulateTimePassing(clockIncrementMillis); - long expectedSystemClockMillis1 = - TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); + long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(utcTime1); // Turn on auto time detection. mScript.simulateAutoTimeDetectionToggle() - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis1, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1) .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); // Turn off auto time detection. @@ -357,8 +345,8 @@ public class TimeDetectorStrategyImplTest { // Simulate more time passing. mScript.simulateTimePassing(clockIncrementMillis); - long expectedSystemClockMillis2 = TimeDetectorStrategy.getTimeAt( - timeSuggestion2.getUtcTime(), mScript.peekElapsedRealtimeMillis()); + long expectedSystemClockMillis2 = + mScript.calculateTimeInMillisForNow(timeSuggestion2.getUtcTime()); // The new time, though valid, should not be set in the system clock because auto time is // disabled. @@ -368,8 +356,7 @@ public class TimeDetectorStrategyImplTest { // Turn on auto time detection. mScript.simulateAutoTimeDetectionToggle() - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis2, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2) .assertLatestPhoneSuggestion(phoneId, timeSuggestion2); } @@ -382,19 +369,21 @@ public class TimeDetectorStrategyImplTest { long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; PhoneTimeSuggestion phoneSuggestion = mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); - int clockIncrementMillis = 1000; - mScript.simulateTimePassing(clockIncrementMillis) - .simulatePhoneTimeSuggestion(phoneSuggestion) + mScript.simulateTimePassing(); + + long expectedSystemClockMillis = + mScript.calculateTimeInMillisForNow(phoneSuggestion.getUtcTime()); + mScript.simulatePhoneTimeSuggestion(phoneSuggestion) .verifySystemClockWasSetAndResetCallTracking( - testTimeMillis + clockIncrementMillis, true /* expectedNetworkBroadcast */) + expectedSystemClockMillis /* expectedNetworkBroadcast */) .assertLatestPhoneSuggestion(phoneId, phoneSuggestion); // Look inside and check what the strategy considers the current best phone suggestion. assertEquals(phoneSuggestion, mScript.peekBestPhoneSuggestion()); // Simulate time passing, long enough that phoneSuggestion is now too old. - mScript.simulateTimePassing(TimeDetectorStrategyImpl.PHONE_MAX_AGE_MILLIS); + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS); // Look inside and check what the strategy considers the current best phone suggestion. It // should still be the, it's just no longer used. @@ -407,15 +396,15 @@ public class TimeDetectorStrategyImplTest { mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) .pokeAutoTimeDetectionEnabled(false); - long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; - ManualTimeSuggestion timeSuggestion = mScript.generateManualTimeSuggestion(testTimeMillis); - final int clockIncrement = 1000; - long expectedSystemClockMillis = testTimeMillis + clockIncrement; + ManualTimeSuggestion timeSuggestion = + mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS); - mScript.simulateTimePassing(clockIncrement) - .simulateManualTimeSuggestion(timeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis, false /* expectNetworkBroadcast */); + mScript.simulateTimePassing(); + + long expectedSystemClockMillis = + mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime()); + mScript.simulateManualTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis); } @Test @@ -430,21 +419,18 @@ public class TimeDetectorStrategyImplTest { long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; PhoneTimeSuggestion phoneTimeSuggestion = mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); - long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue(); - final int clockIncrement = 1000; // Simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - expectedAutoClockMillis += clockIncrement; + mScript.simulateTimePassing(); + long expectedAutoClockMillis = + mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime()); mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedAutoClockMillis, true /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis) .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); // Simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - expectedAutoClockMillis += clockIncrement; + mScript.simulateTimePassing(); // Switch to manual. mScript.simulateAutoTimeDetectionToggle() @@ -452,28 +438,29 @@ public class TimeDetectorStrategyImplTest { .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); // Simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - expectedAutoClockMillis += clockIncrement; + mScript.simulateTimePassing(); // Simulate a manual suggestion 1 day different from the auto suggestion. - long manualTimeMillis = testTimeMillis + ONE_DAY_MILLIS; - long expectedManualClockMillis = manualTimeMillis; + long manualTimeMillis = testTimeMillis + Duration.ofDays(1).toMillis(); ManualTimeSuggestion manualTimeSuggestion = mScript.generateManualTimeSuggestion(manualTimeMillis); + mScript.simulateTimePassing(); + + long expectedManualClockMillis = + mScript.calculateTimeInMillisForNow(manualTimeSuggestion.getUtcTime()); mScript.simulateManualTimeSuggestion(manualTimeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedManualClockMillis, false /* expectNetworkBroadcast */) + .verifySystemClockWasSetAndResetCallTracking(expectedManualClockMillis) .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); // Simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - expectedAutoClockMillis += clockIncrement; + mScript.simulateTimePassing(); // Switch back to auto. mScript.simulateAutoTimeDetectionToggle(); - mScript.verifySystemClockWasSetAndResetCallTracking( - expectedAutoClockMillis, true /* expectNetworkBroadcast */) + expectedAutoClockMillis = + mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime()); + mScript.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis) .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); // Switch back to manual - nothing should happen to the clock. @@ -492,13 +479,139 @@ public class TimeDetectorStrategyImplTest { ManualTimeSuggestion timeSuggestion = mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS); - final int clockIncrement = 1000; - mScript.simulateTimePassing(clockIncrement) + mScript.simulateTimePassing() .simulateManualTimeSuggestion(timeSuggestion) .verifySystemClockWasNotSetAndResetCallTracking(); } + @Test + public void testSuggestNetworkTime_autoTimeEnabled() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true); + + NetworkTimeSuggestion timeSuggestion = + mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS); + + mScript.simulateTimePassing(); + + long expectedSystemClockMillis = + mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime()); + mScript.simulateNetworkTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis); + } + + @Test + public void testSuggestNetworkTime_autoTimeDisabled() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(false); + + NetworkTimeSuggestion timeSuggestion = + mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS); + + mScript.simulateTimePassing() + .simulateNetworkTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestNetworkTime_phoneSuggestionsBeatNetworkSuggestions() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true); + + // Three obviously different times that could not be mistaken for each other. + long networkTimeMillis1 = ARBITRARY_TEST_TIME_MILLIS; + long networkTimeMillis2 = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(30).toMillis(); + long phoneTimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(60).toMillis(); + // A small increment used to simulate the passage of time, but not enough to interfere with + // macro-level time changes associated with suggestion age. + final long smallTimeIncrementMillis = 101; + + // A network suggestion is made. It should be used because there is no phone suggestion. + NetworkTimeSuggestion networkTimeSuggestion1 = + mScript.generateNetworkTimeSuggestion(networkTimeMillis1); + mScript.simulateTimePassing(smallTimeIncrementMillis) + .simulateNetworkTimeSuggestion(networkTimeSuggestion1) + .verifySystemClockWasSetAndResetCallTracking( + mScript.calculateTimeInMillisForNow(networkTimeSuggestion1.getUtcTime())); + + // Check internal state. + mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, null) + .assertLatestNetworkSuggestion(networkTimeSuggestion1); + assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion()); + assertNull(mScript.peekBestPhoneSuggestion()); + + // Simulate a little time passing. + mScript.simulateTimePassing(smallTimeIncrementMillis) + .verifySystemClockWasNotSetAndResetCallTracking(); + + // Now a phone suggestion is made. Phone suggestions are prioritized over network + // suggestions so it should "win". + PhoneTimeSuggestion phoneTimeSuggestion = + mScript.generatePhoneTimeSuggestion(ARBITRARY_PHONE_ID, phoneTimeMillis); + mScript.simulateTimePassing(smallTimeIncrementMillis) + .simulatePhoneTimeSuggestion(phoneTimeSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime())); + + // Check internal state. + mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion) + .assertLatestNetworkSuggestion(networkTimeSuggestion1); + assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion()); + assertEquals(phoneTimeSuggestion, mScript.peekBestPhoneSuggestion()); + + // Simulate some significant time passing: half the time allowed before a time signal + // becomes "too old to use". + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2) + .verifySystemClockWasNotSetAndResetCallTracking(); + + // Now another network suggestion is made. Phone suggestions are prioritized over network + // suggestions so the latest phone suggestion should still "win". + NetworkTimeSuggestion networkTimeSuggestion2 = + mScript.generateNetworkTimeSuggestion(networkTimeMillis2); + mScript.simulateTimePassing(smallTimeIncrementMillis) + .simulateNetworkTimeSuggestion(networkTimeSuggestion2) + .verifySystemClockWasNotSetAndResetCallTracking(); + + // Check internal state. + mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion) + .assertLatestNetworkSuggestion(networkTimeSuggestion2); + assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion()); + assertEquals(phoneTimeSuggestion, mScript.peekBestPhoneSuggestion()); + + // Simulate some significant time passing: half the time allowed before a time signal + // becomes "too old to use". This should mean that phoneTimeSuggestion is now too old to be + // used but networkTimeSuggestion2 is not. + mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2); + + // NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last + // suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle + // to re-run the detection logic. This may change in future but until then we rely on a + // steady stream of suggestions to re-evaluate. + mScript.verifySystemClockWasNotSetAndResetCallTracking(); + + // Check internal state. + mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion) + .assertLatestNetworkSuggestion(networkTimeSuggestion2); + assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion()); + assertNull(mScript.peekBestPhoneSuggestion()); + + // Toggle auto-time off and on to force the detection logic to run. + mScript.simulateAutoTimeDetectionToggle() + .simulateTimePassing(smallTimeIncrementMillis) + .simulateAutoTimeDetectionToggle(); + + // Verify the latest network time now wins. + mScript.verifySystemClockWasSetAndResetCallTracking( + mScript.calculateTimeInMillisForNow(networkTimeSuggestion2.getUtcTime())); + + // Check internal state. + mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion) + .assertLatestNetworkSuggestion(networkTimeSuggestion2); + assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion()); + assertNull(mScript.peekBestPhoneSuggestion()); + } + /** * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving * like the real thing should, it also asserts preconditions. @@ -512,7 +625,6 @@ public class TimeDetectorStrategyImplTest { // Tracking operations. private boolean mSystemClockWasSet; - private Intent mBroadcastSent; @Override public int systemClockUpdateThresholdMillis() { @@ -539,7 +651,6 @@ public class TimeDetectorStrategyImplTest { @Override public long systemClockMillis() { - assertWakeLockAcquired(); return mSystemClockMillis; } @@ -556,12 +667,6 @@ public class TimeDetectorStrategyImplTest { mWakeLockAcquired = false; } - @Override - public void sendStickyBroadcast(Intent intent) { - assertNotNull(intent); - mBroadcastSent = intent; - } - // Methods below are for managing the fake's behavior. void pokeSystemClockUpdateThreshold(int thresholdMillis) { @@ -606,17 +711,8 @@ public class TimeDetectorStrategyImplTest { assertEquals(expectedSystemClockMillis, mSystemClockMillis); } - void verifyIntentWasBroadcast() { - assertTrue(mBroadcastSent != null); - } - - void verifyIntentWasNotBroadcast() { - assertNull(mBroadcastSent); - } - void resetCallTracking() { mSystemClockWasSet = false; - mBroadcastSent = null; } private void assertWakeLockAcquired() { @@ -674,6 +770,11 @@ public class TimeDetectorStrategyImplTest { return this; } + Script simulateNetworkTimeSuggestion(NetworkTimeSuggestion timeSuggestion) { + mTimeDetectorStrategy.suggestNetworkTime(timeSuggestion); + return this; + } + Script simulateAutoTimeDetectionToggle() { mFakeCallback.simulateAutoTimeZoneDetectionToggle(); mTimeDetectorStrategy.handleAutoTimeDetectionChanged(); @@ -685,19 +786,21 @@ public class TimeDetectorStrategyImplTest { return this; } + /** + * Simulates time passing by an arbitrary (but relatively small) amount. + */ + Script simulateTimePassing() { + return simulateTimePassing(999); + } + Script verifySystemClockWasNotSetAndResetCallTracking() { mFakeCallback.verifySystemClockNotSet(); - mFakeCallback.verifyIntentWasNotBroadcast(); mFakeCallback.resetCallTracking(); return this; } - Script verifySystemClockWasSetAndResetCallTracking( - long expectedSystemClockMillis, boolean expectNetworkBroadcast) { + Script verifySystemClockWasSetAndResetCallTracking(long expectedSystemClockMillis) { mFakeCallback.verifySystemClockWasSet(expectedSystemClockMillis); - if (expectNetworkBroadcast) { - mFakeCallback.verifyIntentWasBroadcast(); - } mFakeCallback.resetCallTracking(); return this; } @@ -711,14 +814,30 @@ public class TimeDetectorStrategyImplTest { } /** + * White box test info: Asserts the latest network suggestion is as expected. + */ + Script assertLatestNetworkSuggestion(NetworkTimeSuggestion expected) { + assertEquals(expected, mTimeDetectorStrategy.getLatestNetworkSuggestion()); + return this; + } + + /** * White box test info: Returns the phone suggestion that would be used, if any, given the - * current elapsed real time clock. + * current elapsed real time clock and regardless of origin prioritization. */ PhoneTimeSuggestion peekBestPhoneSuggestion() { return mTimeDetectorStrategy.findBestPhoneSuggestionForTests(); } /** + * White box test info: Returns the network suggestion that would be used, if any, given the + * current elapsed real time clock and regardless of origin prioritization. + */ + NetworkTimeSuggestion peekLatestValidNetworkSuggestion() { + return mTimeDetectorStrategy.findLatestValidNetworkSuggestionForTests(); + } + + /** * Generates a ManualTimeSuggestion using the current elapsed realtime clock for the * reference time. */ @@ -739,6 +858,24 @@ public class TimeDetectorStrategyImplTest { } return createPhoneTimeSuggestion(phoneId, time); } + + /** + * Generates a NetworkTimeSuggestion using the current elapsed realtime clock for the + * reference time. + */ + NetworkTimeSuggestion generateNetworkTimeSuggestion(long timeMillis) { + TimestampedValue<Long> utcTime = + new TimestampedValue<>(mFakeCallback.peekElapsedRealtimeMillis(), timeMillis); + return new NetworkTimeSuggestion(utcTime); + } + + /** + * Calculates what the supplied time would be when adjusted for the movement of the fake + * elapsed realtime clock. + */ + long calculateTimeInMillisForNow(TimestampedValue<Long> utcTime) { + return TimeDetectorStrategy.getTimeAt(utcTime, peekElapsedRealtimeMillis()); + } } private static PhoneTimeSuggestion createPhoneTimeSuggestion(int phoneId, diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java index 239d413c12d2..f1e9191ddb4f 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java @@ -18,7 +18,7 @@ package com.android.server.timedetector; import static org.junit.Assert.assertEquals; -import android.util.TimestampedValue; +import android.os.TimestampedValue; import androidx.test.runner.AndroidJUnit4; diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING new file mode 100644 index 000000000000..d58566673eec --- /dev/null +++ b/telecomm/TEST_MAPPING @@ -0,0 +1,29 @@ +{ + "presubmit": [ + { + "name": "TeleServiceTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelecomUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelephonyProviderTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} + diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java index 8b8c86be7b0a..ea641f866b98 100644 --- a/telecomm/java/android/telecom/AudioState.java +++ b/telecomm/java/android/telecom/AudioState.java @@ -19,7 +19,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 0ebf71fac814..acf51f3856d3 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -20,12 +20,11 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.IBinder; import android.os.ParcelFileDescriptor; import com.android.internal.telecom.IVideoProvider; @@ -575,6 +574,7 @@ public final class Call { private final Bundle mExtras; private final Bundle mIntentExtras; private final long mCreationTimeMillis; + private final String mContactDisplayName; private final @CallDirection int mCallDirection; private final @Connection.VerificationStatus int mCallerNumberVerificationStatus; @@ -882,6 +882,17 @@ public final class Call { } /** + * Returns the name of the caller on the remote end, as derived from a + * {@link android.provider.ContactsContract} lookup of the call's handle. + * @return The name of the caller, or {@code null} if the lookup is not yet complete, if + * there's no contacts entry for the caller, or if the {@link InCallService} does + * not hold the {@link android.Manifest.permission#READ_CONTACTS} permission. + */ + public @Nullable String getContactDisplayName() { + return mContactDisplayName; + } + + /** * Indicates whether the call is an incoming or outgoing call. * @return The call's direction. */ @@ -919,6 +930,7 @@ public final class Call { areBundlesEqual(mExtras, d.mExtras) && areBundlesEqual(mIntentExtras, d.mIntentExtras) && Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) && + Objects.equals(mContactDisplayName, d.mContactDisplayName) && Objects.equals(mCallDirection, d.mCallDirection) && Objects.equals(mCallerNumberVerificationStatus, d.mCallerNumberVerificationStatus); @@ -943,6 +955,7 @@ public final class Call { mExtras, mIntentExtras, mCreationTimeMillis, + mContactDisplayName, mCallDirection, mCallerNumberVerificationStatus); } @@ -965,6 +978,7 @@ public final class Call { Bundle extras, Bundle intentExtras, long creationTimeMillis, + String contactDisplayName, int callDirection, int callerNumberVerificationStatus) { mTelecomCallId = telecomCallId; @@ -983,6 +997,7 @@ public final class Call { mExtras = extras; mIntentExtras = intentExtras; mCreationTimeMillis = creationTimeMillis; + mContactDisplayName = contactDisplayName; mCallDirection = callDirection; mCallerNumberVerificationStatus = callerNumberVerificationStatus; } @@ -1006,6 +1021,7 @@ public final class Call { parcelableCall.getExtras(), parcelableCall.getIntentExtras(), parcelableCall.getCreationTimeMillis(), + parcelableCall.getContactDisplayName(), parcelableCall.getCallDirection(), parcelableCall.getCallerNumberVerificationStatus()); } @@ -1455,6 +1471,7 @@ public final class Call { private boolean mChildrenCached; private String mParentId = null; + private String mActiveGenericConferenceChild = null; private int mState; private List<String> mCannedTextResponses = null; private String mCallingPackage; @@ -1953,6 +1970,20 @@ public final class Call { } /** + * Returns the child {@link Call} in a generic conference that is currently active. + * For calls that are not generic conferences, or when the generic conference has more than + * 2 children, returns {@code null}. + * @see Details#PROPERTY_GENERIC_CONFERENCE + * @return The active child call. + */ + public @Nullable Call getGenericConferenceActiveChildCall() { + if (mActiveGenericConferenceChild != null) { + return mPhone.internalGetCallByTelecomId(mActiveGenericConferenceChild); + } + return null; + } + + /** * Obtains a list of canned, pre-configured message responses to present to the user as * ways of rejecting this {@code Call} using via a text message. * @@ -2200,6 +2231,13 @@ public final class Call { mChildrenCached = false; } + String activeChildCallId = parcelableCall.getActiveChildCallId(); + boolean activeChildChanged = !Objects.equals(activeChildCallId, + mActiveGenericConferenceChild); + if (activeChildChanged) { + mActiveGenericConferenceChild = activeChildCallId; + } + List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds(); List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size()); for (String otherId : conferenceableCallIds) { @@ -2259,7 +2297,7 @@ public final class Call { if (parentChanged) { fireParentChanged(getParent()); } - if (childrenChanged) { + if (childrenChanged || activeChildChanged) { fireChildrenChanged(getChildren()); } if (isRttChanged) { diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java index a5d25e2ce4bb..fb6f99405759 100644 --- a/telecomm/java/android/telecom/CallerInfo.java +++ b/telecomm/java/android/telecom/CallerInfo.java @@ -17,7 +17,7 @@ package android.telecom; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -41,8 +41,8 @@ import com.android.i18n.phonenumbers.NumberParseException; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder; - import com.android.internal.annotations.VisibleForTesting; + import java.util.Locale; diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index a6f79fc71cc3..c934625f588b 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -21,9 +21,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.Notification; import android.bluetooth.BluetoothDevice; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.hardware.camera2.CameraManager; import android.net.Uri; @@ -511,51 +511,116 @@ public abstract class Connection extends Conferenceable { //********************************************************************************************** /** - * Define IMS Audio Codec + * Indicates that the audio codec is currently not specified or is unknown. */ - // Current audio codec is NONE public static final int AUDIO_CODEC_NONE = ImsStreamMediaProfile.AUDIO_QUALITY_NONE; // 0 - // Current audio codec is AMR + /** + * Adaptive Multi-rate audio codec. + */ public static final int AUDIO_CODEC_AMR = ImsStreamMediaProfile.AUDIO_QUALITY_AMR; // 1 - // Current audio codec is AMR_WB + /** + * Adaptive Multi-rate wideband audio codec. + */ public static final int AUDIO_CODEC_AMR_WB = ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB; // 2 - // Current audio codec is QCELP13K + /** + * Qualcomm code-excited linear prediction 13 kilobit audio codec. + */ public static final int AUDIO_CODEC_QCELP13K = ImsStreamMediaProfile.AUDIO_QUALITY_QCELP13K; //3 - // Current audio codec is EVRC + /** + * Enhanced Variable Rate Codec. See 3GPP2 C.S0014-A. + */ public static final int AUDIO_CODEC_EVRC = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC; // 4 - // Current audio codec is EVRC_B + /** + * Enhanced Variable Rate Codec B. Commonly used on CDMA networks. + */ public static final int AUDIO_CODEC_EVRC_B = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_B; // 5 - // Current audio codec is EVRC_WB + /** + * Enhanced Variable Rate Wideband Codec. See RFC5188. + */ public static final int AUDIO_CODEC_EVRC_WB = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_WB; // 6 - // Current audio codec is EVRC_NW + /** + * Enhanced Variable Rate Narrowband-Wideband Codec. + */ public static final int AUDIO_CODEC_EVRC_NW = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_NW; // 7 - // Current audio codec is GSM_EFR + /** + * GSM Enhanced Full-Rate audio codec, also known as GSM-EFR, GSM 06.60, or simply EFR. + */ public static final int AUDIO_CODEC_GSM_EFR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_EFR; // 8 - // Current audio codec is GSM_FR + /** + * GSM Full-Rate audio codec, also known as GSM-FR, GSM 06.10, GSM, or simply FR. + */ public static final int AUDIO_CODEC_GSM_FR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_FR; // 9 - // Current audio codec is GSM_HR + /** + * GSM Half Rate audio codec. + */ public static final int AUDIO_CODEC_GSM_HR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_HR; // 10 - // Current audio codec is G711U + /** + * ITU-T G711U audio codec. + */ public static final int AUDIO_CODEC_G711U = ImsStreamMediaProfile.AUDIO_QUALITY_G711U; // 11 - // Current audio codec is G723 + /** + * ITU-T G723 audio codec. + */ public static final int AUDIO_CODEC_G723 = ImsStreamMediaProfile.AUDIO_QUALITY_G723; // 12 - // Current audio codec is G711A + /** + * ITU-T G711A audio codec. + */ public static final int AUDIO_CODEC_G711A = ImsStreamMediaProfile.AUDIO_QUALITY_G711A; // 13 - // Current audio codec is G722 + /** + * ITU-T G722 audio codec. + */ public static final int AUDIO_CODEC_G722 = ImsStreamMediaProfile.AUDIO_QUALITY_G722; // 14 - // Current audio codec is G711AB + /** + * ITU-T G711AB audio codec. + */ public static final int AUDIO_CODEC_G711AB = ImsStreamMediaProfile.AUDIO_QUALITY_G711AB; // 15 - // Current audio codec is G729 + /** + * ITU-T G729 audio codec. + */ public static final int AUDIO_CODEC_G729 = ImsStreamMediaProfile.AUDIO_QUALITY_G729; // 16 - // Current audio codec is EVS_NB + /** + * Enhanced Voice Services Narrowband audio codec. See 3GPP TS 26.441. + */ public static final int AUDIO_CODEC_EVS_NB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_NB; // 17 - // Current audio codec is EVS_WB + /** + * Enhanced Voice Services Wideband audio codec. See 3GPP TS 26.441. + */ public static final int AUDIO_CODEC_EVS_WB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_WB; // 18 - // Current audio codec is EVS_SWB + /** + * Enhanced Voice Services Super-Wideband audio codec. See 3GPP TS 26.441. + */ public static final int AUDIO_CODEC_EVS_SWB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB; // 19 - // Current audio codec is EVS_FB + /** + * Enhanced Voice Services Fullband audio codec. See 3GPP TS 26.441. + */ public static final int AUDIO_CODEC_EVS_FB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_FB; // 20 + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "AUDIO_CODEC_", value = { + AUDIO_CODEC_NONE, + AUDIO_CODEC_AMR, + AUDIO_CODEC_AMR_WB, + AUDIO_CODEC_QCELP13K, + AUDIO_CODEC_EVRC, + AUDIO_CODEC_EVRC_B, + AUDIO_CODEC_EVRC_WB, + AUDIO_CODEC_EVRC_NW, + AUDIO_CODEC_GSM_EFR, + AUDIO_CODEC_GSM_FR, + AUDIO_CODEC_GSM_HR, + AUDIO_CODEC_G711U, + AUDIO_CODEC_G723, + AUDIO_CODEC_G711A, + AUDIO_CODEC_G722, + AUDIO_CODEC_G711AB, + AUDIO_CODEC_G729, + AUDIO_CODEC_EVS_NB, + AUDIO_CODEC_EVS_SWB, + AUDIO_CODEC_EVS_FB + }) + public @interface AudioCodec {} + /** * Connection extra key used to store the last forwarded number associated with the current * connection. Used to communicate to the user interface that the connection was forwarded via @@ -649,10 +714,10 @@ public abstract class Connection extends Conferenceable { "android.telecom.extra.IS_RTT_AUDIO_PRESENT"; /** - * The audio codec in use for the current {@link Connection}, if known. Valid values include - * {@link #AUDIO_CODEC_AMR_WB} and {@link #AUDIO_CODEC_EVS_WB}. + * The audio codec in use for the current {@link Connection}, if known. Examples of valid + * values include {@link #AUDIO_CODEC_AMR_WB} and {@link #AUDIO_CODEC_EVS_WB}. */ - public static final String EXTRA_AUDIO_CODEC = + public static final @AudioCodec String EXTRA_AUDIO_CODEC = "android.telecom.extra.AUDIO_CODEC"; /** diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java index 7d4ee7686512..4f6a9d6450f8 100644 --- a/telecomm/java/android/telecom/Log.java +++ b/telecomm/java/android/telecom/Log.java @@ -16,7 +16,7 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.Uri; import android.os.Build; diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index a234bb0af8fa..415a817b58d5 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -16,27 +16,286 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.telecom.Call.Details.CallDirection; +import com.android.internal.telecom.IVideoProvider; + import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.android.internal.telecom.IVideoProvider; - /** * Information about a call that is used between InCallService and Telecom. * @hide */ public final class ParcelableCall implements Parcelable { + + public static class ParcelableCallBuilder { + private String mId; + private int mState; + private DisconnectCause mDisconnectCause; + private List<String> mCannedSmsResponses; + private int mCapabilities; + private int mProperties; + private int mSupportedAudioRoutes; + private long mConnectTimeMillis; + private Uri mHandle; + private int mHandlePresentation; + private String mCallerDisplayName; + private int mCallerDisplayNamePresentation; + private GatewayInfo mGatewayInfo; + private PhoneAccountHandle mAccountHandle; + private boolean mIsVideoCallProviderChanged; + private IVideoProvider mVideoCallProvider; + private boolean mIsRttCallChanged; + private ParcelableRttCall mRttCall; + private String mParentCallId; + private List<String> mChildCallIds; + private StatusHints mStatusHints; + private int mVideoState; + private List<String> mConferenceableCallIds; + private Bundle mIntentExtras; + private Bundle mExtras; + private long mCreationTimeMillis; + private int mCallDirection; + private int mCallerNumberVerificationStatus; + private String mContactDisplayName; + private String mActiveChildCallId; + + public ParcelableCallBuilder setId(String id) { + mId = id; + return this; + } + + public ParcelableCallBuilder setState(int state) { + mState = state; + return this; + } + + public ParcelableCallBuilder setDisconnectCause(DisconnectCause disconnectCause) { + mDisconnectCause = disconnectCause; + return this; + } + + public ParcelableCallBuilder setCannedSmsResponses(List<String> cannedSmsResponses) { + mCannedSmsResponses = cannedSmsResponses; + return this; + } + + public ParcelableCallBuilder setCapabilities(int capabilities) { + mCapabilities = capabilities; + return this; + } + + public ParcelableCallBuilder setProperties(int properties) { + mProperties = properties; + return this; + } + + public ParcelableCallBuilder setSupportedAudioRoutes(int supportedAudioRoutes) { + mSupportedAudioRoutes = supportedAudioRoutes; + return this; + } + + public ParcelableCallBuilder setConnectTimeMillis(long connectTimeMillis) { + mConnectTimeMillis = connectTimeMillis; + return this; + } + + public ParcelableCallBuilder setHandle(Uri handle) { + mHandle = handle; + return this; + } + + public ParcelableCallBuilder setHandlePresentation(int handlePresentation) { + mHandlePresentation = handlePresentation; + return this; + } + + public ParcelableCallBuilder setCallerDisplayName(String callerDisplayName) { + mCallerDisplayName = callerDisplayName; + return this; + } + + public ParcelableCallBuilder setCallerDisplayNamePresentation( + int callerDisplayNamePresentation) { + mCallerDisplayNamePresentation = callerDisplayNamePresentation; + return this; + } + + public ParcelableCallBuilder setGatewayInfo(GatewayInfo gatewayInfo) { + mGatewayInfo = gatewayInfo; + return this; + } + + public ParcelableCallBuilder setAccountHandle(PhoneAccountHandle accountHandle) { + mAccountHandle = accountHandle; + return this; + } + + public ParcelableCallBuilder setIsVideoCallProviderChanged( + boolean isVideoCallProviderChanged) { + mIsVideoCallProviderChanged = isVideoCallProviderChanged; + return this; + } + + public ParcelableCallBuilder setVideoCallProvider(IVideoProvider videoCallProvider) { + mVideoCallProvider = videoCallProvider; + return this; + } + + public ParcelableCallBuilder setIsRttCallChanged(boolean isRttCallChanged) { + mIsRttCallChanged = isRttCallChanged; + return this; + } + + public ParcelableCallBuilder setRttCall(ParcelableRttCall rttCall) { + mRttCall = rttCall; + return this; + } + + public ParcelableCallBuilder setParentCallId(String parentCallId) { + mParentCallId = parentCallId; + return this; + } + + public ParcelableCallBuilder setChildCallIds(List<String> childCallIds) { + mChildCallIds = childCallIds; + return this; + } + + public ParcelableCallBuilder setStatusHints(StatusHints statusHints) { + mStatusHints = statusHints; + return this; + } + + public ParcelableCallBuilder setVideoState(int videoState) { + mVideoState = videoState; + return this; + } + + public ParcelableCallBuilder setConferenceableCallIds( + List<String> conferenceableCallIds) { + mConferenceableCallIds = conferenceableCallIds; + return this; + } + + public ParcelableCallBuilder setIntentExtras(Bundle intentExtras) { + mIntentExtras = intentExtras; + return this; + } + + public ParcelableCallBuilder setExtras(Bundle extras) { + mExtras = extras; + return this; + } + + public ParcelableCallBuilder setCreationTimeMillis(long creationTimeMillis) { + mCreationTimeMillis = creationTimeMillis; + return this; + } + + public ParcelableCallBuilder setCallDirection(int callDirection) { + mCallDirection = callDirection; + return this; + } + + public ParcelableCallBuilder setCallerNumberVerificationStatus( + int callerNumberVerificationStatus) { + mCallerNumberVerificationStatus = callerNumberVerificationStatus; + return this; + } + + public ParcelableCallBuilder setContactDisplayName(String contactDisplayName) { + mContactDisplayName = contactDisplayName; + return this; + } + + public ParcelableCallBuilder setActiveChildCallId(String activeChildCallId) { + mActiveChildCallId = activeChildCallId; + return this; + } + + public ParcelableCall createParcelableCall() { + return new ParcelableCall( + mId, + mState, + mDisconnectCause, + mCannedSmsResponses, + mCapabilities, + mProperties, + mSupportedAudioRoutes, + mConnectTimeMillis, + mHandle, + mHandlePresentation, + mCallerDisplayName, + mCallerDisplayNamePresentation, + mGatewayInfo, + mAccountHandle, + mIsVideoCallProviderChanged, + mVideoCallProvider, + mIsRttCallChanged, + mRttCall, + mParentCallId, + mChildCallIds, + mStatusHints, + mVideoState, + mConferenceableCallIds, + mIntentExtras, + mExtras, + mCreationTimeMillis, + mCallDirection, + mCallerNumberVerificationStatus, + mContactDisplayName, + mActiveChildCallId); + } + + public static ParcelableCallBuilder fromParcelableCall(ParcelableCall parcelableCall) { + ParcelableCallBuilder newBuilder = new ParcelableCallBuilder(); + newBuilder.mId = parcelableCall.mId; + newBuilder.mState = parcelableCall.mState; + newBuilder.mDisconnectCause = parcelableCall.mDisconnectCause; + newBuilder.mCannedSmsResponses = parcelableCall.mCannedSmsResponses; + newBuilder.mCapabilities = parcelableCall.mCapabilities; + newBuilder.mProperties = parcelableCall.mProperties; + newBuilder.mSupportedAudioRoutes = parcelableCall.mSupportedAudioRoutes; + newBuilder.mConnectTimeMillis = parcelableCall.mConnectTimeMillis; + newBuilder.mHandle = parcelableCall.mHandle; + newBuilder.mHandlePresentation = parcelableCall.mHandlePresentation; + newBuilder.mCallerDisplayName = parcelableCall.mCallerDisplayName; + newBuilder.mCallerDisplayNamePresentation = + parcelableCall.mCallerDisplayNamePresentation; + newBuilder.mGatewayInfo = parcelableCall.mGatewayInfo; + newBuilder.mAccountHandle = parcelableCall.mAccountHandle; + newBuilder.mIsVideoCallProviderChanged = parcelableCall.mIsVideoCallProviderChanged; + newBuilder.mVideoCallProvider = parcelableCall.mVideoCallProvider; + newBuilder.mIsRttCallChanged = parcelableCall.mIsRttCallChanged; + newBuilder.mRttCall = parcelableCall.mRttCall; + newBuilder.mParentCallId = parcelableCall.mParentCallId; + newBuilder.mChildCallIds = parcelableCall.mChildCallIds; + newBuilder.mStatusHints = parcelableCall.mStatusHints; + newBuilder.mVideoState = parcelableCall.mVideoState; + newBuilder.mConferenceableCallIds = parcelableCall.mConferenceableCallIds; + newBuilder.mIntentExtras = parcelableCall.mIntentExtras; + newBuilder.mExtras = parcelableCall.mExtras; + newBuilder.mCreationTimeMillis = parcelableCall.mCreationTimeMillis; + newBuilder.mCallDirection = parcelableCall.mCallDirection; + newBuilder.mCallerNumberVerificationStatus = + parcelableCall.mCallerNumberVerificationStatus; + newBuilder.mContactDisplayName = parcelableCall.mContactDisplayName; + newBuilder.mActiveChildCallId = parcelableCall.mActiveChildCallId; + return newBuilder; + } + } + private final String mId; private final int mState; private final DisconnectCause mDisconnectCause; @@ -66,6 +325,8 @@ public final class ParcelableCall implements Parcelable { private final long mCreationTimeMillis; private final int mCallDirection; private final int mCallerNumberVerificationStatus; + private final String mContactDisplayName; + private final String mActiveChildCallId; // Only valid for CDMA conferences public ParcelableCall( String id, @@ -95,7 +356,10 @@ public final class ParcelableCall implements Parcelable { Bundle extras, long creationTimeMillis, int callDirection, - int callerNumberVerificationStatus) { + int callerNumberVerificationStatus, + String contactDisplayName, + String activeChildCallId + ) { mId = id; mState = state; mDisconnectCause = disconnectCause; @@ -124,6 +388,8 @@ public final class ParcelableCall implements Parcelable { mCreationTimeMillis = creationTimeMillis; mCallDirection = callDirection; mCallerNumberVerificationStatus = callerNumberVerificationStatus; + mContactDisplayName = contactDisplayName; + mActiveChildCallId = activeChildCallId; } /** The unique ID of the call. */ @@ -333,6 +599,21 @@ public final class ParcelableCall implements Parcelable { return mCallerNumberVerificationStatus; } + /** + * @return the name of the remote party as derived from a contacts DB lookup. + */ + public @Nullable String getContactDisplayName() { + return mContactDisplayName; + } + + /** + * @return On a CDMA conference with two participants, returns the ID of the child call that's + * currently active. + */ + public @Nullable String getActiveChildCallId() { + return mActiveChildCallId; + } + /** Responsible for creating ParcelableCall objects for deserialized Parcels. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCall> CREATOR = @@ -372,35 +653,40 @@ public final class ParcelableCall implements Parcelable { long creationTimeMillis = source.readLong(); int callDirection = source.readInt(); int callerNumberVerificationStatus = source.readInt(); - return new ParcelableCall( - id, - state, - disconnectCause, - cannedSmsResponses, - capabilities, - properties, - supportedAudioRoutes, - connectTimeMillis, - handle, - handlePresentation, - callerDisplayName, - callerDisplayNamePresentation, - gatewayInfo, - accountHandle, - isVideoCallProviderChanged, - videoCallProvider, - isRttCallChanged, - rttCall, - parentCallId, - childCallIds, - statusHints, - videoState, - conferenceableCallIds, - intentExtras, - extras, - creationTimeMillis, - callDirection, - callerNumberVerificationStatus); + String contactDisplayName = source.readString(); + String activeChildCallId = source.readString(); + return new ParcelableCallBuilder() + .setId(id) + .setState(state) + .setDisconnectCause(disconnectCause) + .setCannedSmsResponses(cannedSmsResponses) + .setCapabilities(capabilities) + .setProperties(properties) + .setSupportedAudioRoutes(supportedAudioRoutes) + .setConnectTimeMillis(connectTimeMillis) + .setHandle(handle) + .setHandlePresentation(handlePresentation) + .setCallerDisplayName(callerDisplayName) + .setCallerDisplayNamePresentation(callerDisplayNamePresentation) + .setGatewayInfo(gatewayInfo) + .setAccountHandle(accountHandle) + .setIsVideoCallProviderChanged(isVideoCallProviderChanged) + .setVideoCallProvider(videoCallProvider) + .setIsRttCallChanged(isRttCallChanged) + .setRttCall(rttCall) + .setParentCallId(parentCallId) + .setChildCallIds(childCallIds) + .setStatusHints(statusHints) + .setVideoState(videoState) + .setConferenceableCallIds(conferenceableCallIds) + .setIntentExtras(intentExtras) + .setExtras(extras) + .setCreationTimeMillis(creationTimeMillis) + .setCallDirection(callDirection) + .setCallerNumberVerificationStatus(callerNumberVerificationStatus) + .setContactDisplayName(contactDisplayName) + .setActiveChildCallId(activeChildCallId) + .createParcelableCall(); } @Override @@ -447,6 +733,8 @@ public final class ParcelableCall implements Parcelable { destination.writeLong(mCreationTimeMillis); destination.writeInt(mCallDirection); destination.writeInt(mCallerNumberVerificationStatus); + destination.writeString(mContactDisplayName); + destination.writeString(mActiveChildCallId); } @Override diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index 61a639a1a235..a427ed612b31 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -17,8 +17,8 @@ package android.telecom; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.util.ArrayMap; diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java index eb568e04ebf3..e1bcb5fbdf00 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -18,7 +18,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Build; import android.os.Parcel; diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 68f5bf637ce2..f1dca0387369 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -26,7 +26,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -848,6 +848,17 @@ public class TelecomManager { */ public static final int PRESENTATION_PAYPHONE = 4; + + /* + * Values for the adb property "persist.radio.videocall.audio.output" + */ + /** @hide */ + public static final int AUDIO_OUTPUT_ENABLE_SPEAKER = 0; + /** @hide */ + public static final int AUDIO_OUTPUT_DISABLE_SPEAKER = 1; + /** @hide */ + public static final int AUDIO_OUTPUT_DEFAULT = AUDIO_OUTPUT_ENABLE_SPEAKER; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java index 4a1aa0a8ffa4..109e7f829f2e 100644 --- a/telecomm/java/android/telecom/VideoCallImpl.java +++ b/telecomm/java/android/telecom/VideoCallImpl.java @@ -16,7 +16,7 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Handler; diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java index 64e6ca3416e3..4197f3cfc6c3 100644 --- a/telecomm/java/android/telecom/VideoProfile.java +++ b/telecomm/java/android/telecom/VideoProfile.java @@ -19,7 +19,6 @@ package android.telecom; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/OWNERS b/telephony/OWNERS index 2a6e8deeb13e..58a7ea08da3f 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -14,4 +14,5 @@ shuoq@google.com refuhoo@google.com paulye@google.com nazaninb@google.com -sarahchin@google.com
\ No newline at end of file +sarahchin@google.com +dbright@google.com diff --git a/telephony/TEST_MAPPING b/telephony/TEST_MAPPING new file mode 100644 index 000000000000..d58566673eec --- /dev/null +++ b/telephony/TEST_MAPPING @@ -0,0 +1,29 @@ +{ + "presubmit": [ + { + "name": "TeleServiceTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelecomUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelephonyProviderTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} + diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java index d4526a48fdb1..8ac675502527 100644 --- a/telephony/java/android/telephony/LocationAccessPolicy.java +++ b/telephony/common/android/telephony/LocationAccessPolicy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -11,13 +11,14 @@ * 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 + * limitations under the License. */ package android.telephony; import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; @@ -59,8 +60,10 @@ public final class LocationAccessPolicy { DENIED_HARD, } + /** Data structure for location permission query */ public static class LocationPermissionQuery { public final String callingPackage; + public final String callingFeatureId; public final int callingUid; public final int callingPid; public final int minSdkVersionForCoarse; @@ -68,10 +71,11 @@ public final class LocationAccessPolicy { public final boolean logAsInfo; public final String method; - private LocationPermissionQuery(String callingPackage, int callingUid, int callingPid, - int minSdkVersionForCoarse, int minSdkVersionForFine, boolean logAsInfo, - String method) { + private LocationPermissionQuery(String callingPackage, @Nullable String callingFeatureId, + int callingUid, int callingPid, int minSdkVersionForCoarse, + int minSdkVersionForFine, boolean logAsInfo, String method) { this.callingPackage = callingPackage; + this.callingFeatureId = callingFeatureId; this.callingUid = callingUid; this.callingPid = callingPid; this.minSdkVersionForCoarse = minSdkVersionForCoarse; @@ -80,8 +84,10 @@ public final class LocationAccessPolicy { this.method = method; } + /** Builder for LocationPermissionQuery */ public static class Builder { private String mCallingPackage; + private String mCallingFeatureId; private int mCallingUid; private int mCallingPid; private int mMinSdkVersionForCoarse = Integer.MAX_VALUE; @@ -100,6 +106,11 @@ public final class LocationAccessPolicy { /** * Mandatory parameter, used for performing permission checks. */ + public Builder setCallingFeatureId(@Nullable String callingFeatureId) { + mCallingFeatureId = callingFeatureId; + return this; + } + public Builder setCallingUid(int callingUid) { mCallingUid = callingUid; return this; @@ -149,9 +160,10 @@ public final class LocationAccessPolicy { return this; } + /** build LocationPermissionQuery */ public LocationPermissionQuery build() { - return new LocationPermissionQuery(mCallingPackage, mCallingUid, - mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine, + return new LocationPermissionQuery(mCallingPackage, mCallingFeatureId, + mCallingUid, mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine, mLogAsInfo, mMethod); } } @@ -235,6 +247,7 @@ public final class LocationAccessPolicy { } } + /** Check if location permissions have been granted */ public static LocationPermissionResult checkLocationPermission( Context context, LocationPermissionQuery query) { // Always allow the phone process and system server to access location. This avoid @@ -341,4 +354,4 @@ public final class LocationAccessPolicy { } return false; } -}
\ No newline at end of file +} diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index 0630454cbf53..3f5aa0f86b75 100644 --- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * 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. @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.internal.telephony; @@ -24,10 +24,10 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.RemoteException; import android.provider.Settings; +import android.util.Log; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -73,11 +73,11 @@ public final class CarrierAppUtils { * system startup prior to any application running, as well as any time the set of carrier * privileged apps may have changed. */ - public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage, + public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, IPackageManager packageManager, TelephonyManager telephonyManager, ContentResolver contentResolver, int userId) { if (DEBUG) { - Slog.d(TAG, "disableCarrierAppsUntilPrivileged"); + Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } SystemConfig config = SystemConfig.getInstance(); ArraySet<String> systemCarrierAppsDisabledUntilUsed = @@ -100,10 +100,10 @@ public final class CarrierAppUtils { * broadcasts. The app will continue to run (briefly) after being disabled, before the Package * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. */ - public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage, + public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, IPackageManager packageManager, ContentResolver contentResolver, int userId) { if (DEBUG) { - Slog.d(TAG, "disableCarrierAppsUntilPrivileged"); + Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } SystemConfig config = SystemConfig.getInstance(); ArraySet<String> systemCarrierAppsDisabledUntilUsed = @@ -117,7 +117,10 @@ public final class CarrierAppUtils { systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed); } - // Must be public b/c framework unit tests can't access package-private methods. + /** + * Disable carrier apps until they are privileged + * Must be public b/c framework unit tests can't access package-private methods. + */ @VisibleForTesting public static void disableCarrierAppsUntilPrivileged(String callingPackage, IPackageManager packageManager, @Nullable TelephonyManager telephonyManager, @@ -166,12 +169,12 @@ public final class CarrierAppUtils { // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. if (!ai.isUpdatedSystemApp() - && (ai.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - || ai.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + && (ai.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + || ai.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) { - Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user " + Log.i(TAG, "Update state(" + packageName + "): ENABLED for user " + userId); packageManager.setSystemAppInstallState( packageName, @@ -188,13 +191,13 @@ public final class CarrierAppUtils { // Also enable any associated apps for this carrier app. if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - if (associatedApp.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - || associatedApp.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + if (associatedApp.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + || associatedApp.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED || (associatedApp.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { - Slog.i(TAG, "Update associated state(" + associatedApp.packageName + Log.i(TAG, "Update associated state(" + associatedApp.packageName + "): ENABLED for user " + userId); packageManager.setSystemAppInstallState( associatedApp.packageName, @@ -216,10 +219,10 @@ public final class CarrierAppUtils { // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. if (!ai.isUpdatedSystemApp() - && ai.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + && ai.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { - Slog.i(TAG, "Update state(" + packageName + Log.i(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED for user " + userId); packageManager.setSystemAppInstallState( packageName, @@ -237,7 +240,7 @@ public final class CarrierAppUtils { == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && (associatedApp.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { - Slog.i(TAG, + Log.i(TAG, "Update associated state(" + associatedApp.packageName + "): DISABLED_UNTIL_USED for user " + userId); packageManager.setSystemAppInstallState( @@ -265,7 +268,7 @@ public final class CarrierAppUtils { packageManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId); } } catch (RemoteException e) { - Slog.w(TAG, "Could not reach PackageManager", e); + Log.w(TAG, "Could not reach PackageManager", e); } } @@ -291,8 +294,8 @@ public final class CarrierAppUtils { ApplicationInfo ai = candidates.get(i); String packageName = ai.packageName; boolean hasPrivileges = - telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) == - TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; if (!hasPrivileges) { candidates.remove(i); } @@ -387,7 +390,7 @@ public final class CarrierAppUtils { return ai; } } catch (RemoteException e) { - Slog.w(TAG, "Could not reach PackageManager", e); + Log.w(TAG, "Could not reach PackageManager", e); } return null; } diff --git a/telephony/common/com/android/internal/telephony/EncodeException.java b/telephony/common/com/android/internal/telephony/EncodeException.java index cdc853e09895..bb723a0f47b3 100644 --- a/telephony/common/com/android/internal/telephony/EncodeException.java +++ b/telephony/common/com/android/internal/telephony/EncodeException.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * {@hide} diff --git a/telephony/common/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java index 79d366037f08..60cd40094950 100644 --- a/telephony/common/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/common/com/android/internal/telephony/GsmAlphabet.java @@ -16,10 +16,10 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.os.Build; -import android.telephony.Rlog; +import android.util.Log; import android.text.TextUtils; import android.util.SparseIntArray; @@ -496,11 +496,11 @@ public class GsmAlphabet { StringBuilder ret = new StringBuilder(lengthSeptets); if (languageTable < 0 || languageTable > sLanguageTables.length) { - Rlog.w(TAG, "unknown language table " + languageTable + ", using default"); + Log.w(TAG, "unknown language table " + languageTable + ", using default"); languageTable = 0; } if (shiftTable < 0 || shiftTable > sLanguageShiftTables.length) { - Rlog.w(TAG, "unknown single shift table " + shiftTable + ", using default"); + Log.w(TAG, "unknown single shift table " + shiftTable + ", using default"); shiftTable = 0; } @@ -510,11 +510,11 @@ public class GsmAlphabet { String shiftTableToChar = sLanguageShiftTables[shiftTable]; if (languageTableToChar.isEmpty()) { - Rlog.w(TAG, "no language table for code " + languageTable + ", using default"); + Log.w(TAG, "no language table for code " + languageTable + ", using default"); languageTableToChar = sLanguageTables[0]; } if (shiftTableToChar.isEmpty()) { - Rlog.w(TAG, "no single shift table for code " + shiftTable + ", using default"); + Log.w(TAG, "no single shift table for code " + shiftTable + ", using default"); shiftTableToChar = sLanguageShiftTables[0]; } @@ -554,7 +554,7 @@ public class GsmAlphabet { } } } catch (RuntimeException ex) { - Rlog.e(TAG, "Error GSM 7 bit packed: ", ex); + Log.e(TAG, "Error GSM 7 bit packed: ", ex); return null; } @@ -811,7 +811,7 @@ public class GsmAlphabet { for (int i = 0; i < sz; i++) { char c = s.charAt(i); if (c == GSM_EXTENDED_ESCAPE) { - Rlog.w(TAG, "countGsmSeptets() string contains Escape character, skipping."); + Log.w(TAG, "countGsmSeptets() string contains Escape character, skipping."); continue; } if (charToLanguageTable.get(c, -1) != -1) { @@ -890,7 +890,7 @@ public class GsmAlphabet { for (int i = 0; i < sz && !lpcList.isEmpty(); i++) { char c = s.charAt(i); if (c == GSM_EXTENDED_ESCAPE) { - Rlog.w(TAG, "countGsmSeptets() string contains Escape character, ignoring!"); + Log.w(TAG, "countGsmSeptets() string contains Escape character, ignoring!"); continue; } // iterate through enabled locking shift tables @@ -1494,7 +1494,7 @@ public class GsmAlphabet { int numTables = sLanguageTables.length; int numShiftTables = sLanguageShiftTables.length; if (numTables != numShiftTables) { - Rlog.e(TAG, "Error: language tables array length " + numTables + + Log.e(TAG, "Error: language tables array length " + numTables + " != shift tables array length " + numShiftTables); } @@ -1504,7 +1504,7 @@ public class GsmAlphabet { int tableLen = table.length(); if (tableLen != 0 && tableLen != 128) { - Rlog.e(TAG, "Error: language tables index " + i + + Log.e(TAG, "Error: language tables index " + i + " length " + tableLen + " (expected 128 or 0)"); } @@ -1522,7 +1522,7 @@ public class GsmAlphabet { int shiftTableLen = shiftTable.length(); if (shiftTableLen != 0 && shiftTableLen != 128) { - Rlog.e(TAG, "Error: language shift tables index " + i + + Log.e(TAG, "Error: language shift tables index " + i + " length " + shiftTableLen + " (expected 128 or 0)"); } diff --git a/telephony/common/com/android/internal/telephony/HbpcdUtils.java b/telephony/common/com/android/internal/telephony/HbpcdUtils.java index 2f3194214be6..714f5a673633 100644 --- a/telephony/common/com/android/internal/telephony/HbpcdUtils.java +++ b/telephony/common/com/android/internal/telephony/HbpcdUtils.java @@ -19,7 +19,7 @@ package com.android.internal.telephony; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; -import android.telephony.Rlog; +import android.util.Log; import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch; import com.android.internal.telephony.HbpcdLookup.MccIdd; @@ -54,16 +54,16 @@ public final class HbpcdUtils { if (c2 != null) { int c2Counter = c2.getCount(); if (DBG) { - Rlog.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter); + Log.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter); } if (c2Counter == 1) { if (DBG) { - Rlog.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2); + Log.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2); } c2.moveToFirst(); tmpMcc = c2.getInt(0); if (DBG) { - Rlog.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc); + Log.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc); } c2.close(); return tmpMcc; @@ -85,18 +85,18 @@ public final class HbpcdUtils { int c3Counter = c3.getCount(); if (c3Counter > 0) { if (c3Counter > 1) { - Rlog.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3); + Log.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3); } - if (DBG) Rlog.d(LOG_TAG, "Query conflict sid returned the cursor " + c3); + if (DBG) Log.d(LOG_TAG, "Query conflict sid returned the cursor " + c3); c3.moveToFirst(); tmpMcc = c3.getInt(0); if (DBG) { - Rlog.d(LOG_TAG, "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc); + Log.d(LOG_TAG, "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc); } if (!isNitzTimeZone) { // time zone is not accurate, it may get wrong mcc, ignore it. if (DBG) { - Rlog.d(LOG_TAG, "time zone is not accurate, mcc may be " + tmpMcc); + Log.d(LOG_TAG, "time zone is not accurate, mcc may be " + tmpMcc); } tmpMcc = 0; } @@ -115,18 +115,18 @@ public final class HbpcdUtils { null, null); if (c5 != null) { if (c5.getCount() > 0) { - if (DBG) Rlog.d(LOG_TAG, "Query Range returned the cursor " + c5); + if (DBG) Log.d(LOG_TAG, "Query Range returned the cursor " + c5); c5.moveToFirst(); tmpMcc = c5.getInt(0); - if (DBG) Rlog.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc); + if (DBG) Log.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc); c5.close(); return tmpMcc; } c5.close(); } - if (DBG) Rlog.d(LOG_TAG, "SID NOT found in mcc_sid_range."); + if (DBG) Log.d(LOG_TAG, "SID NOT found in mcc_sid_range."); - if (DBG) Rlog.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc = " + tmpMcc); + if (DBG) Log.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc = " + tmpMcc); // If unknown MCC still could not be resolved, return tmpMcc; } @@ -135,7 +135,7 @@ public final class HbpcdUtils { * Gets country information with given MCC. */ public String getIddByMcc(int mcc) { - if (DBG) Rlog.d(LOG_TAG, "Enter getHbpcdInfoByMCC."); + if (DBG) Log.d(LOG_TAG, "Enter getHbpcdInfoByMCC."); String idd = ""; Cursor c = null; @@ -145,19 +145,19 @@ public final class HbpcdUtils { MccIdd.MCC + "=" + mcc, null, null); if (cur != null) { if (cur.getCount() > 0) { - if (DBG) Rlog.d(LOG_TAG, "Query Idd returned the cursor " + cur); + if (DBG) Log.d(LOG_TAG, "Query Idd returned the cursor " + cur); // TODO: for those country having more than 1 IDDs, need more information // to decide which IDD would be used. currently just use the first 1. cur.moveToFirst(); idd = cur.getString(0); - if (DBG) Rlog.d(LOG_TAG, "IDD = " + idd); + if (DBG) Log.d(LOG_TAG, "IDD = " + idd); } cur.close(); } if (c != null) c.close(); - if (DBG) Rlog.d(LOG_TAG, "Exit getHbpcdInfoByMCC."); + if (DBG) Log.d(LOG_TAG, "Exit getHbpcdInfoByMCC."); return idd; } } diff --git a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java index 922af126e73e..0b47547d3b0c 100644 --- a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java +++ b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java @@ -24,17 +24,17 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.UserHandle; -import com.android.internal.os.BackgroundThread; - /** * Helper class for monitoring the state of packages: adding, removing, * updating, and disappearing and reappearing on the SD card. */ public abstract class PackageChangeReceiver extends BroadcastReceiver { static final IntentFilter sPackageIntentFilter = new IntentFilter(); + private static HandlerThread sHandlerThread; static { sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -43,28 +43,24 @@ public abstract class PackageChangeReceiver extends BroadcastReceiver { sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); sPackageIntentFilter.addDataScheme("package"); } + // Keep an instance of Context around as long as we still want the receiver: + // if the instance of Context gets garbage-collected, it'll unregister the receiver, so only + // unset when we want to unregister. Context mRegisteredContext; /** - * To register the intents that needed for monitoring the state of packages + * To register the intents that needed for monitoring the state of packages. Once this method + * has been called on an instance of {@link PackageChangeReceiver}, all subsequent calls must + * have the same {@code user} argument. */ public void register(@NonNull Context context, @Nullable Looper thread, @Nullable UserHandle user) { if (mRegisteredContext != null) { throw new IllegalStateException("Already registered"); } - Handler handler = (thread == null) ? BackgroundThread.getHandler() : new Handler(thread); - mRegisteredContext = context; - if (handler != null) { - if (user != null) { - context.registerReceiverAsUser(this, user, sPackageIntentFilter, null, handler); - } else { - context.registerReceiver(this, sPackageIntentFilter, - null, handler); - } - } else { - throw new NullPointerException(); - } + Handler handler = new Handler(thread == null ? getStaticLooper() : thread); + mRegisteredContext = user == null ? context : context.createContextAsUser(user, 0); + mRegisteredContext.registerReceiver(this, sPackageIntentFilter, null, handler); } /** @@ -78,6 +74,14 @@ public abstract class PackageChangeReceiver extends BroadcastReceiver { mRegisteredContext = null; } + private static synchronized Looper getStaticLooper() { + if (sHandlerThread == null) { + sHandlerThread = new HandlerThread(PackageChangeReceiver.class.getSimpleName()); + sHandlerThread.start(); + } + return sHandlerThread.getLooper(); + } + /** * This method is invoked when receive the Intent.ACTION_PACKAGE_ADDED */ diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java index df668ea2313d..3a900d9c224f 100644 --- a/telephony/common/com/android/internal/telephony/SmsApplication.java +++ b/telephony/common/com/android/internal/telephony/SmsApplication.java @@ -20,6 +20,7 @@ import android.Manifest.permission; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.role.RoleManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -40,15 +41,14 @@ import android.os.UserHandle; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; import android.telephony.PackageChangeReceiver; -import android.telephony.Rlog; +import android.util.Log; import android.telephony.TelephonyManager; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -57,7 +57,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; - +import java.util.stream.Collectors; /** @@ -67,10 +67,10 @@ import java.util.function.Consumer; */ public final class SmsApplication { static final String LOG_TAG = "SmsApplication"; - private static final String PHONE_PACKAGE_NAME = "com.android.phone"; - private static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth"; - private static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service"; - private static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony"; + public static final String PHONE_PACKAGE_NAME = "com.android.phone"; + public static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth"; + public static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service"; + public static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony"; private static final String SCHEME_SMS = "sms"; private static final String SCHEME_SMSTO = "smsto"; @@ -79,13 +79,13 @@ public final class SmsApplication { private static final boolean DEBUG = false; private static final boolean DEBUG_MULTIUSER = false; - private static final int[] DEFAULT_APP_EXCLUSIVE_APPOPS = { - AppOpsManager.OP_READ_SMS, - AppOpsManager.OP_WRITE_SMS, - AppOpsManager.OP_RECEIVE_SMS, - AppOpsManager.OP_RECEIVE_WAP_PUSH, - AppOpsManager.OP_SEND_SMS, - AppOpsManager.OP_READ_CELL_BROADCASTS + private static final String[] DEFAULT_APP_EXCLUSIVE_APPOPS = { + AppOpsManager.OPSTR_READ_SMS, + AppOpsManager.OPSTR_WRITE_SMS, + AppOpsManager.OPSTR_RECEIVE_SMS, + AppOpsManager.OPSTR_RECEIVE_WAP_PUSH, + AppOpsManager.OPSTR_SEND_SMS, + AppOpsManager.OPSTR_READ_CELL_BROADCASTS }; private static SmsPackageMonitor sSmsPackageMonitor = null; @@ -249,6 +249,7 @@ public final class SmsApplication { private static Collection<SmsApplicationData> getApplicationCollectionInternal( Context context, int userId) { PackageManager packageManager = context.getPackageManager(); + UserHandle userHandle = UserHandle.of(userId); // Get the list of apps registered for SMS Intent intent = new Intent(Intents.SMS_DELIVER_ACTION); @@ -257,7 +258,7 @@ public final class SmsApplication { } List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userId); + userHandle); HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>(); @@ -284,7 +285,7 @@ public final class SmsApplication { intent.setDataAndType(null, "application/vnd.wap.mms-message"); List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userId); + userHandle); for (ResolveInfo resolveInfo : mmsReceivers) { final ActivityInfo activityInfo = resolveInfo.activityInfo; if (activityInfo == null) { @@ -326,7 +327,7 @@ public final class SmsApplication { Uri.fromParts(SCHEME_SMSTO, "", null)); List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userId); + userHandle); for (ResolveInfo resolveInfo : sendToActivities) { final ActivityInfo activityInfo = resolveInfo.activityInfo; if (activityInfo == null) { @@ -344,7 +345,7 @@ public final class SmsApplication { List<ResolveInfo> smsAppChangedReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); if (DEBUG_MULTIUSER) { Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" + smsAppChangedReceivers); @@ -371,7 +372,7 @@ public final class SmsApplication { List<ResolveInfo> providerChangedReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); if (DEBUG_MULTIUSER) { Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" + providerChangedReceivers); @@ -398,7 +399,7 @@ public final class SmsApplication { List<ResolveInfo> simFullReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); if (DEBUG_MULTIUSER) { Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers=" + simFullReceivers); @@ -501,7 +502,7 @@ public final class SmsApplication { // If we found a package, make sure AppOps permissions are set up correctly if (applicationData != null) { - // We can only call checkOp if we are privileged (updateIfNeeded) or if the app we + // We can only call unsafeCheckOp if we are privileged (updateIfNeeded) or if the app we // are checking is for our current uid. Doing this check from the unprivileged current // SMS app allows us to tell the current SMS app that it is not in a good state and // needs to ask to be the current SMS app again to work properly. @@ -555,23 +556,23 @@ public final class SmsApplication { // apps, all of them should be able to write to telephony provider. // This is to allow the proxy package permission check in telephony provider // to pass. - for (int appop : DEFAULT_APP_EXCLUSIVE_APPOPS) { - appOps.setUidMode(appop, Process.PHONE_UID, AppOpsManager.MODE_ALLOWED); + for (String opStr : DEFAULT_APP_EXCLUSIVE_APPOPS) { + appOps.setUidMode(opStr, Process.PHONE_UID, AppOpsManager.MODE_ALLOWED); } } private static boolean tryFixExclusiveSmsAppops(Context context, SmsApplicationData applicationData, boolean updateIfNeeded) { AppOpsManager appOps = context.getSystemService(AppOpsManager.class); - for (int appOp : DEFAULT_APP_EXCLUSIVE_APPOPS) { - int mode = appOps.checkOp(appOp, applicationData.mUid, + for (String opStr : DEFAULT_APP_EXCLUSIVE_APPOPS) { + int mode = appOps.unsafeCheckOp(opStr, applicationData.mUid, applicationData.mPackageName); if (mode != AppOpsManager.MODE_ALLOWED) { - Rlog.e(LOG_TAG, applicationData.mPackageName + " lost " - + AppOpsManager.modeToName(appOp) + ": " + Log.e(LOG_TAG, applicationData.mPackageName + " lost " + + opStr + ": " + (updateIfNeeded ? " (fixing)" : " (no permission to fix)")); if (updateIfNeeded) { - appOps.setUidMode(appOp, applicationData.mUid, AppOpsManager.MODE_ALLOWED); + appOps.setUidMode(opStr, applicationData.mUid, AppOpsManager.MODE_ALLOWED); } else { return false; } @@ -630,7 +631,8 @@ public final class SmsApplication { } // We only make the change if the new package is valid - PackageManager packageManager = context.getPackageManager(); + PackageManager packageManager = + context.createContextAsUser(userHandle, 0).getPackageManager(); Collection<SmsApplicationData> applications = getApplicationCollectionInternal( context, userId); SmsApplicationData oldAppData = oldPackageName != null ? @@ -641,11 +643,10 @@ public final class SmsApplication { AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); if (oldPackageName != null) { try { - int uid = packageManager.getPackageInfoAsUser( - oldPackageName, 0, userId).applicationInfo.uid; + int uid = packageManager.getPackageInfo(oldPackageName, 0).applicationInfo.uid; setExclusiveAppops(oldPackageName, appOps, uid, AppOpsManager.MODE_DEFAULT); } catch (NameNotFoundException e) { - Rlog.w(LOG_TAG, "Old SMS package not found: " + oldPackageName); + Log.w(LOG_TAG, "Old SMS package not found: " + oldPackageName); } } @@ -752,29 +753,29 @@ public final class SmsApplication { // the package signature matches system signature. final int result = packageManager.checkSignatures(context.getPackageName(), packageName); if (result != PackageManager.SIGNATURE_MATCH) { - Rlog.e(LOG_TAG, packageName + " does not have system signature"); + Log.e(LOG_TAG, packageName + " does not have system signature"); return; } try { PackageInfo info = packageManager.getPackageInfo(packageName, 0); - int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, + int mode = appOps.unsafeCheckOp(AppOpsManager.OPSTR_WRITE_SMS, info.applicationInfo.uid, packageName); if (mode != AppOpsManager.MODE_ALLOWED) { - Rlog.w(LOG_TAG, packageName + " does not have OP_WRITE_SMS: (fixing)"); + Log.w(LOG_TAG, packageName + " does not have OP_WRITE_SMS: (fixing)"); setExclusiveAppops(packageName, appOps, info.applicationInfo.uid, AppOpsManager.MODE_ALLOWED); } } catch (NameNotFoundException e) { // No whitelisted system app on this device - Rlog.e(LOG_TAG, "Package not found: " + packageName); + Log.e(LOG_TAG, "Package not found: " + packageName); } } private static void setExclusiveAppops(String pkg, AppOpsManager appOpsManager, int uid, int mode) { - for (int appop : DEFAULT_APP_EXCLUSIVE_APPOPS) { - appOpsManager.setUidMode(appop, uid, mode); + for (String opStr : DEFAULT_APP_EXCLUSIVE_APPOPS) { + appOpsManager.setUidMode(opStr, uid, mode); } } @@ -806,9 +807,16 @@ public final class SmsApplication { } private void onPackageChanged() { - PackageManager packageManager = mContext.getPackageManager(); + int userId; + try { + userId = getSendingUser().getIdentifier(); + } catch (NullPointerException e) { + // This should never happen in prod -- unit tests will put the receiver into a + // unusual state where the pending result is null, which produces a NPE when calling + // getSendingUserId. Just pretend like it's the system user for testing. + userId = UserHandle.USER_SYSTEM; + } Context userContext = mContext; - final int userId = getSendingUserId(); if (userId != UserHandle.USER_SYSTEM) { try { userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0, @@ -819,10 +827,11 @@ public final class SmsApplication { } } } + PackageManager packageManager = userContext.getPackageManager(); // Ensure this component is still configured as the preferred activity ComponentName componentName = getDefaultSendToApplication(userContext, true); if (componentName != null) { - configurePreferredActivity(packageManager, componentName, userId); + configurePreferredActivity(packageManager, componentName); } } } @@ -834,41 +843,36 @@ public final class SmsApplication { @UnsupportedAppUsage private static void configurePreferredActivity(PackageManager packageManager, - ComponentName componentName, int userId) { + ComponentName componentName) { // Add the four activity preferences we want to direct to this app. - replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMS); - replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMSTO); - replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMS); - replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMSTO); + replacePreferredActivity(packageManager, componentName, SCHEME_SMS); + replacePreferredActivity(packageManager, componentName, SCHEME_SMSTO); + replacePreferredActivity(packageManager, componentName, SCHEME_MMS); + replacePreferredActivity(packageManager, componentName, SCHEME_MMSTO); } /** * Updates the ACTION_SENDTO activity to the specified component for the specified scheme. */ private static void replacePreferredActivity(PackageManager packageManager, - ComponentName componentName, int userId, String scheme) { + ComponentName componentName, String scheme) { // Build the set of existing activities that handle this scheme Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(scheme, "", null)); - List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivitiesAsUser( - intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER, - userId); + List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities( + intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER); - // Build the set of ComponentNames for these activities - final int n = resolveInfoList.size(); - ComponentName[] set = new ComponentName[n]; - for (int i = 0; i < n; i++) { - ResolveInfo info = resolveInfoList.get(i); - set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); - } + List<ComponentName> components = resolveInfoList.stream().map(info -> + new ComponentName(info.activityInfo.packageName, info.activityInfo.name)) + .collect(Collectors.toList()); // Update the preferred SENDTO activity for the specified scheme IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SENDTO); intentFilter.addCategory(Intent.CATEGORY_DEFAULT); intentFilter.addDataScheme(scheme); - packageManager.replacePreferredActivityAsUser(intentFilter, + packageManager.replacePreferredActivity(intentFilter, IntentFilter.MATCH_CATEGORY_SCHEME + IntentFilter.MATCH_ADJUSTMENT_NORMAL, - set, componentName, userId); + components, componentName); } /** @@ -899,6 +903,7 @@ public final class SmsApplication { * @param userId target user ID. * @return component name of the app and class to deliver SMS messages to */ + @VisibleForTesting public static ComponentName getDefaultSmsApplicationAsUser(Context context, boolean updateIfNeeded, int userId) { final long token = Binder.clearCallingIdentity(); diff --git a/telephony/common/com/android/internal/telephony/SmsConstants.java b/telephony/common/com/android/internal/telephony/SmsConstants.java index 19f52b0ef429..3aa8bbf607d1 100644 --- a/telephony/common/com/android/internal/telephony/SmsConstants.java +++ b/telephony/common/com/android/internal/telephony/SmsConstants.java @@ -15,7 +15,7 @@ */ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * SMS Constants and must be the same as the corresponding diff --git a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java index 06c08f56aa1f..cd365a113189 100644 --- a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java +++ b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java @@ -24,13 +24,16 @@ import android.os.PersistableBundle; import android.os.SystemProperties; import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; -import android.telephony.Rlog; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; import com.android.internal.telephony.HbpcdLookup.MccIdd; import com.android.internal.telephony.HbpcdLookup.MccLookup; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; @@ -143,7 +146,7 @@ public class SmsNumberUtils { // First check whether the number is a NANP number. int nanpState = checkNANP(numberEntry, allIDDs); - if (DBG) Rlog.d(TAG, "NANP type: " + getNumberPlanType(nanpState)); + if (DBG) Log.d(TAG, "NANP type: " + getNumberPlanType(nanpState)); if ((nanpState == NP_NANP_LOCAL) || (nanpState == NP_NANP_AREA_LOCAL) @@ -173,7 +176,7 @@ public class SmsNumberUtils { int internationalState = checkInternationalNumberPlan(context, numberEntry, allIDDs, NANP_IDD); - if (DBG) Rlog.d(TAG, "International type: " + getNumberPlanType(internationalState)); + if (DBG) Log.d(TAG, "International type: " + getNumberPlanType(internationalState)); String returnNumber = null; switch (internationalState) { @@ -272,7 +275,7 @@ public class SmsNumberUtils { } } } catch (SQLException e) { - Rlog.e(TAG, "Can't access HbpcdLookup database", e); + Log.e(TAG, "Can't access HbpcdLookup database", e); } finally { if (cursor != null) { cursor.close(); @@ -281,7 +284,7 @@ public class SmsNumberUtils { IDDS_MAPS.put(mcc, allIDDs); - if (DBG) Rlog.d(TAG, "MCC = " + mcc + ", all IDDs = " + allIDDs); + if (DBG) Log.d(TAG, "MCC = " + mcc + ", all IDDs = " + allIDDs); return allIDDs; } @@ -472,7 +475,7 @@ public class SmsNumberUtils { int tempCC = allCCs[i]; for (int j = 0; j < MAX_COUNTRY_CODES_LENGTH; j ++) { if (tempCC == ccArray[j]) { - if (DBG) Rlog.d(TAG, "Country code = " + tempCC); + if (DBG) Log.d(TAG, "Country code = " + tempCC); return tempCC; } } @@ -509,7 +512,7 @@ public class SmsNumberUtils { } } } catch (SQLException e) { - Rlog.e(TAG, "Can't access HbpcdLookup database", e); + Log.e(TAG, "Can't access HbpcdLookup database", e); } finally { if (cursor != null) { cursor.close(); @@ -561,10 +564,10 @@ public class SmsNumberUtils { * Filter the destination number if using VZW sim card. */ public static String filterDestAddr(Context context, int subId, String destAddr) { - if (DBG) Rlog.d(TAG, "enter filterDestAddr. destAddr=\"" + Rlog.pii(TAG, destAddr) + "\"" ); + if (DBG) Log.d(TAG, "enter filterDestAddr. destAddr=\"" + pii(TAG, destAddr) + "\"" ); if (destAddr == null || !PhoneNumberUtils.isGlobalPhoneNumber(destAddr)) { - Rlog.w(TAG, "destAddr" + Rlog.pii(TAG, destAddr) + + Log.w(TAG, "destAddr" + pii(TAG, destAddr) + " is not a global phone number! Nothing changed."); return destAddr; } @@ -585,9 +588,9 @@ public class SmsNumberUtils { } if (DBG) { - Rlog.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted.")); - Rlog.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? Rlog.pii(TAG, - result) : Rlog.pii(TAG, destAddr)) + "\""); + Log.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted.")); + Log.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? pii(TAG, + result) : pii(TAG, destAddr)) + "\""); } return result != null ? result : destAddr; } @@ -608,7 +611,7 @@ public class SmsNumberUtils { networkType = CDMA_HOME_NETWORK; } } else { - if (DBG) Rlog.w(TAG, "warning! unknown mPhoneType value=" + phoneType); + if (DBG) Log.w(TAG, "warning! unknown mPhoneType value=" + phoneType); } return networkType; @@ -650,4 +653,44 @@ public class SmsNumberUtils { // by default this value is false return false; } + + /** + * Redact personally identifiable information for production users. + * @param tag used to identify the source of a log message + * @param pii the personally identifiable information we want to apply secure hash on. + * @return If tag is loggable in verbose mode or pii is null, return the original input. + * otherwise return a secure Hash of input pii + */ + private static String pii(String tag, Object pii) { + String val = String.valueOf(pii); + if (pii == null || TextUtils.isEmpty(val) || Log.isLoggable(tag, Log.VERBOSE)) { + return val; + } + return "[" + secureHash(val.getBytes()) + "]"; + } + + /** + * Returns a secure hash (using the SHA1 algorithm) of the provided input. + * + * @return "****" if the build type is user, otherwise the hash + * @param input the bytes for which the secure hash should be computed. + */ + private static String secureHash(byte[] input) { + // Refrain from logging user personal information in user build. + if (android.os.Build.IS_USER) { + return "****"; + } + + MessageDigest messageDigest; + + try { + messageDigest = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + return "####"; + } + + byte[] result = messageDigest.digest(input); + return Base64.encodeToString( + result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP); + } } diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 606fd5b89791..5beb06d8595a 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.Manifest; +import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -26,10 +27,7 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.Build; import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; -import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; @@ -41,7 +39,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.Supplier; /** Utility class for Telephony permission enforcement. */ public final class TelephonyPermissions { @@ -49,9 +46,6 @@ public final class TelephonyPermissions { private static final boolean DBG = false; - private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () -> - ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); - /** * Whether to disable the new device identifier access restrictions. */ @@ -95,16 +89,19 @@ public final class TelephonyPermissions { * inaccesible to carrier-privileged apps). */ public static boolean checkCallingOrSelfReadPhoneState( - Context context, int subId, String callingPackage, String message) { + Context context, int subId, String callingPackage, @Nullable String callingFeatureId, + String message) { return checkReadPhoneState(context, subId, Binder.getCallingPid(), Binder.getCallingUid(), - callingPackage, message); + callingPackage, callingFeatureId, message); } /** Identical to checkCallingOrSelfReadPhoneState but never throws SecurityException */ public static boolean checkCallingOrSelfReadPhoneStateNoThrow( - Context context, int subId, String callingPackage, String message) { + Context context, int subId, String callingPackage, @Nullable String callingFeatureId, + String message) { try { - return checkCallingOrSelfReadPhoneState(context, subId, callingPackage, message); + return checkCallingOrSelfReadPhoneState(context, subId, callingPackage, + callingFeatureId, message); } catch (SecurityException se) { return false; } @@ -132,49 +129,8 @@ public final class TelephonyPermissions { * devices. */ public static boolean checkReadPhoneState( - Context context, int subId, int pid, int uid, String callingPackage, String message) { - return checkReadPhoneState( - context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, message); - } - - /** - * Check whether the calling packages has carrier privileges for the passing subscription. - * @return {@code true} if the caller has carrier privileges, {@false} otherwise. - */ - public static boolean checkCarrierPrivilegeForSubId(int subId) { - if (SubscriptionManager.isValidSubscriptionId(subId) - && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid()) - == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { - return true; - } - return false; - } - - /** - * Check whether the app with the given pid/uid can read phone state. - * - * <p>This method behaves in one of the following ways: - * <ul> - * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the - * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId. - * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for - * apps which support runtime permissions, if the caller does not currently have any of - * these permissions. - * <li>return false: if the caller lacks all of these permissions and doesn't support runtime - * permissions. This implies that the user revoked the ability to read phone state - * manually (via AppOps). In this case we can't throw as it would break app compatibility, - * so we return false to indicate that the calling function should return dummy data. - * </ul> - * - * <p>Note: for simplicity, this method always returns false for callers using legacy - * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged. - * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+ - * devices. - */ - @VisibleForTesting - public static boolean checkReadPhoneState( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, - String callingPackage, String message) { + Context context, int subId, int pid, int uid, String callingPackage, + @Nullable String callingFeatureId, String message) { try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); @@ -189,7 +145,7 @@ public final class TelephonyPermissions { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for reading phone state. if (SubscriptionManager.isValidSubscriptionId(subId)) { - enforceCarrierPrivilege(telephonySupplier, subId, uid, message); + enforceCarrierPrivilege(context, subId, uid, message); return true; } throw phoneStateException; @@ -204,23 +160,16 @@ public final class TelephonyPermissions { } /** - * Check whether the app with the given pid/uid can read phone state, or has carrier - * privileges on any active subscription. - * - * <p>If the app does not have carrier privilege, this method will return {@code false} instead - * of throwing a SecurityException. Therefore, the callers cannot tell the difference - * between M+ apps which declare the runtime permission but do not have it, and pre-M apps - * which declare the static permission but had access revoked via AppOps. Apps in the former - * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for - * use only if the behavior in both scenarios is meant to be identical. - * - * @return {@code true} if the app can read phone state or has carrier privilege; - * {@code false} otherwise. + * Check whether the calling packages has carrier privileges for the passing subscription. + * @return {@code true} if the caller has carrier privileges, {@false} otherwise. */ - public static boolean checkReadPhoneStateOnAnyActiveSub( - Context context, int pid, int uid, String callingPackage, String message) { - return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid, - callingPackage, message); + public static boolean checkCarrierPrivilegeForSubId(Context context, int subId) { + if (SubscriptionManager.isValidSubscriptionId(subId) + && getCarrierPrivilegeStatus(context, subId, Binder.getCallingUid()) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return true; + } + return false; } /** @@ -237,10 +186,8 @@ public final class TelephonyPermissions { * @return {@code true} if the app can read phone state or has carrier privilege; * {@code false} otherwise. */ - @VisibleForTesting - public static boolean checkReadPhoneStateOnAnyActiveSub( - Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid, - String callingPackage, String message) { + public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid, + String callingPackage, @Nullable String callingFeatureId, String message) { try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); @@ -254,7 +201,7 @@ public final class TelephonyPermissions { } catch (SecurityException phoneStateException) { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for reading phone state. - return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid); + return checkCarrierPrivilegeForAnySubId(context, uid); } } @@ -283,9 +230,10 @@ public final class TelephonyPermissions { * </ul> */ public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, - String callingPackage, String message) { + String callingPackage, @Nullable String callingFeatureId, String message) { return checkCallingOrSelfReadDeviceIdentifiers(context, - SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message); + SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, callingFeatureId, + message); } /** @@ -306,9 +254,9 @@ public final class TelephonyPermissions { * </ul> */ public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId, - String callingPackage, String message) { + String callingPackage, @Nullable String callingFeatureId, String message) { return checkPrivilegedReadPermissionOrCarrierPrivilegePermission( - context, subId, callingPackage, message, true); + context, subId, callingPackage, callingFeatureId, message, true); } /** @@ -328,9 +276,9 @@ public final class TelephonyPermissions { * </ul> */ public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId, - String callingPackage, String message) { + String callingPackage, @Nullable String callingFeatureId, String message) { return checkPrivilegedReadPermissionOrCarrierPrivilegePermission( - context, subId, callingPackage, message, false); + context, subId, callingPackage, callingFeatureId, message, false); } /** @@ -352,8 +300,8 @@ public final class TelephonyPermissions { * </ul> */ private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission( - Context context, int subId, String callingPackage, String message, - boolean allowCarrierPrivilegeOnAnySub) { + Context context, int subId, String callingPackage, @Nullable String callingFeatureId, + String message, boolean allowCarrierPrivilegeOnAnySub) { int uid = Binder.getCallingUid(); int pid = Binder.getCallingPid(); // Allow system and root access to the device identifiers. @@ -368,12 +316,11 @@ public final class TelephonyPermissions { } // If the calling package has carrier privileges for specified sub, then allow access. - if (checkCarrierPrivilegeForSubId(subId)) return true; + if (checkCarrierPrivilegeForSubId(context, subId)) return true; // If the calling package has carrier privileges for any subscription // and allowCarrierPrivilegeOnAnySub is set true, then allow access. - if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId( - context, TELEPHONY_SUPPLIER, uid)) { + if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) { return true; } @@ -465,7 +412,7 @@ public final class TelephonyPermissions { uid) == PackageManager.PERMISSION_GRANTED) { return false; } - if (checkCarrierPrivilegeForSubId(subId)) { + if (checkCarrierPrivilegeForSubId(context, subId)) { return false; } } @@ -479,27 +426,14 @@ public final class TelephonyPermissions { * to it, {@code false} otherwise. */ public static boolean checkReadCallLog( - Context context, int subId, int pid, int uid, String callingPackage) { - return checkReadCallLog( - context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage); - } - - /** - * Check whether the app with the given pid/uid can read the call log. - * @return {@code true} if the specified app has the read call log permission and AppOpp granted - * to it, {@code false} otherwise. - */ - @VisibleForTesting - public static boolean checkReadCallLog( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, - String callingPackage) { - + Context context, int subId, int pid, int uid, String callingPackage, + @Nullable String callingPackageName) { if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid) != PERMISSION_GRANTED) { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for being able to see the call phone numbers. if (SubscriptionManager.isValidSubscriptionId(subId)) { - enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog"); + enforceCarrierPrivilege(context, subId, uid, "readCallLog"); return true; } return false; @@ -519,10 +453,11 @@ public final class TelephonyPermissions { * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers. */ public static boolean checkCallingOrSelfReadPhoneNumber( - Context context, int subId, String callingPackage, String message) { + Context context, int subId, String callingPackage, @Nullable String callingFeatureId, + String message) { return checkReadPhoneNumber( - context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(), - callingPackage, message); + context, subId, Binder.getCallingPid(), Binder.getCallingUid(), + callingPackage, callingFeatureId, message); } /** @@ -533,8 +468,8 @@ public final class TelephonyPermissions { */ @VisibleForTesting public static boolean checkReadPhoneNumber( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, - String callingPackage, String message) { + Context context, int subId, int pid, int uid, + String callingPackage, @Nullable String callingFeatureId, String message) { // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); if (appOps.noteOp(AppOpsManager.OPSTR_WRITE_SMS, uid, callingPackage) == @@ -548,7 +483,8 @@ public final class TelephonyPermissions { // First, check if we can read the phone state. try { return checkReadPhoneState( - context, telephonySupplier, subId, pid, uid, callingPackage, message); + context, subId, pid, uid, callingPackage, callingFeatureId, + message); } catch (SecurityException readPhoneStateSecurityException) { } // Can be read with READ_SMS too. @@ -588,8 +524,8 @@ public final class TelephonyPermissions { return; } - if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next."); - enforceCallingOrSelfCarrierPrivilege(subId, message); + if (DBG) Log.d(LOG_TAG, "No modify permission, check carrier privilege next."); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -606,10 +542,10 @@ public final class TelephonyPermissions { } if (DBG) { - Rlog.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next."); + Log.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next."); } - enforceCallingOrSelfCarrierPrivilege(subId, message); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -626,11 +562,38 @@ public final class TelephonyPermissions { } if (DBG) { - Rlog.d(LOG_TAG, "No READ_PRIVILEDED_PHONE_STATE permission, " + Log.d(LOG_TAG, "No READ_PRIVILEGED_PHONE_STATE permission, " + "check carrier privilege next."); } - enforceCallingOrSelfCarrierPrivilege(subId, message); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); + } + + /** + * Ensure the caller (or self, if not processing an IPC) has + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or carrier privileges. + * + * @throws SecurityException if the caller does not have the required permission/privileges + */ + public static void enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege( + Context context, int subId, String message) { + if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + == PERMISSION_GRANTED) { + return; + } + + if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + == PERMISSION_GRANTED) { + return; + } + + if (DBG) { + Log.d(LOG_TAG, "No READ_PRIVILEGED_PHONE_STATE nor READ_PRECISE_PHONE_STATE permission" + + ", check carrier privilege next."); + } + + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -638,35 +601,31 @@ public final class TelephonyPermissions { * * @throws SecurityException if the caller does not have the required privileges */ - public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) { + public static void enforceCallingOrSelfCarrierPrivilege( + Context context, int subId, String message) { // NOTE: It's critical that we explicitly pass the calling UID here rather than call // TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from // the phone process. When called from another process, it will check whether that process // has carrier privileges instead. - enforceCarrierPrivilege(subId, Binder.getCallingUid(), message); - } - - private static void enforceCarrierPrivilege(int subId, int uid, String message) { - enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message); + enforceCarrierPrivilege(context, subId, Binder.getCallingUid(), message); } private static void enforceCarrierPrivilege( - Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) { - if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid) + Context context, int subId, int uid, String message) { + if (getCarrierPrivilegeStatus(context, subId, uid) != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { - if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege."); + if (DBG) Log.e(LOG_TAG, "No Carrier Privilege."); throw new SecurityException(message); } } /** Returns whether the provided uid has carrier privileges for any active subscription ID. */ - private static boolean checkCarrierPrivilegeForAnySubId( - Context context, Supplier<ITelephony> telephonySupplier, int uid) { + private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) { SubscriptionManager sm = (SubscriptionManager) context.getSystemService( Context.TELEPHONY_SUBSCRIPTION_SERVICE); int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false); for (int activeSubId : activeSubIds) { - if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid) + if (getCarrierPrivilegeStatus(context, activeSubId, uid) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return true; } @@ -674,18 +633,15 @@ public final class TelephonyPermissions { return false; } - private static int getCarrierPrivilegeStatus( - Supplier<ITelephony> telephonySupplier, int subId, int uid) { - ITelephony telephony = telephonySupplier.get(); + private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) { + final long identity = Binder.clearCallingIdentity(); try { - if (telephony != null) { - return telephony.getCarrierPrivilegeStatusForUid(subId, uid); - } - } catch (RemoteException e) { - // Fallback below. + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid); + } finally { + Binder.restoreCallingIdentity(identity); } - Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges"); - return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; } /** diff --git a/telephony/java/com/android/internal/telephony/util/ArrayUtils.java b/telephony/common/com/android/internal/telephony/util/ArrayUtils.java index 2905125c69cc..28401a6a7092 100644 --- a/telephony/java/com/android/internal/telephony/util/ArrayUtils.java +++ b/telephony/common/com/android/internal/telephony/util/ArrayUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -29,17 +29,30 @@ public final class ArrayUtils { /** * Adds value to given array if not already present, providing set-like behavior. + * + * @param kind The class of the array elements. + * @param array The array to append to. + * @param element The array element to append. + * @return The array containing the appended element. */ @SuppressWarnings("unchecked") - public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) { + @NonNull + public static <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) { return appendElement(kind, array, element, false); } /** * Adds value to given array. + * + * @param kind The class of the array elements. + * @param array The array to append to. + * @param element The array element to append. + * @param allowDuplicates Whether to allow duplicated elements in array. + * @return The array containing the appended element. */ @SuppressWarnings("unchecked") - public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element, + @NonNull + public static <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element, boolean allowDuplicates) { final T[] result; final int end; @@ -59,13 +72,14 @@ public final class ArrayUtils { /** * Combine multiple arrays into a single array. * - * @param kind The class of the array elements + * @param kind The class of the array elements * @param arrays The arrays to combine - * @param <T> The class of the array elements (inferred from kind). + * @param <T> The class of the array elements (inferred from kind). * @return A single array containing all the elements of the parameter arrays. */ @SuppressWarnings("unchecked") - public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) { + @NonNull + public static <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) { if (arrays == null || arrays.length == 0) { return createEmptyArray(kind); } diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java index 0498d7c31406..0498d7c31406 100644 --- a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java +++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java diff --git a/telephony/common/com/google/android/mms/ContentType.java b/telephony/common/com/google/android/mms/ContentType.java index 12e4b7e26e1e..4a971dd34c8f 100644 --- a/telephony/common/com/google/android/mms/ContentType.java +++ b/telephony/common/com/google/android/mms/ContentType.java @@ -17,7 +17,7 @@ package com.google.android.mms; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.ArrayList; diff --git a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java index 2836c3075b3b..55087ff0fb1d 100644 --- a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java +++ b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java @@ -17,7 +17,7 @@ package com.google.android.mms; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Thrown when an invalid header value was set. diff --git a/telephony/common/com/google/android/mms/MmsException.java b/telephony/common/com/google/android/mms/MmsException.java index 5be33ed1fac9..24bceb37f590 100644 --- a/telephony/common/com/google/android/mms/MmsException.java +++ b/telephony/common/com/google/android/mms/MmsException.java @@ -17,7 +17,7 @@ package com.google.android.mms; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A generic exception that is thrown by the Mms client. diff --git a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java index ae447d7a7417..8693385bb032 100644 --- a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java +++ b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/Base64.java b/telephony/common/com/google/android/mms/pdu/Base64.java index 483fa7f9842e..0d6a46a59fcc 100644 --- a/telephony/common/com/google/android/mms/pdu/Base64.java +++ b/telephony/common/com/google/android/mms/pdu/Base64.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class Base64 { /** diff --git a/telephony/common/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java index 27da35e2d928..5172b7b67f88 100644 --- a/telephony/common/com/google/android/mms/pdu/CharacterSets.java +++ b/telephony/common/com/google/android/mms/pdu/CharacterSets.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.UnsupportedEncodingException; import java.util.HashMap; diff --git a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java index 7093ac63338c..8fb6a7545abf 100644 --- a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java +++ b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java index 41662750842f..8c0380f77cdd 100644 --- a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java +++ b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java @@ -17,10 +17,9 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; diff --git a/telephony/common/com/google/android/mms/pdu/GenericPdu.java b/telephony/common/com/google/android/mms/pdu/GenericPdu.java index ebf16ac7e632..320b13ffed2b 100644 --- a/telephony/common/com/google/android/mms/pdu/GenericPdu.java +++ b/telephony/common/com/google/android/mms/pdu/GenericPdu.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java index e108f7600baf..42a89c69e873 100644 --- a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java +++ b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/NotificationInd.java b/telephony/common/com/google/android/mms/pdu/NotificationInd.java index b561bd4ab3a7..ca4615c2e9fe 100644 --- a/telephony/common/com/google/android/mms/pdu/NotificationInd.java +++ b/telephony/common/com/google/android/mms/pdu/NotificationInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java index 3c70f86a0890..ebd81afc0173 100644 --- a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java +++ b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/PduBody.java b/telephony/common/com/google/android/mms/pdu/PduBody.java index 51914e4110b0..f7f285f653b9 100644 --- a/telephony/common/com/google/android/mms/pdu/PduBody.java +++ b/telephony/common/com/google/android/mms/pdu/PduBody.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.HashMap; import java.util.Map; diff --git a/telephony/common/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java index e24bf21a11b5..b8b212c493aa 100644 --- a/telephony/common/com/google/android/mms/pdu/PduComposer.java +++ b/telephony/common/com/google/android/mms/pdu/PduComposer.java @@ -17,12 +17,11 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.text.TextUtils; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; diff --git a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java index 8551b2f9b693..57141fedf1e0 100644 --- a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java +++ b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class PduContentTypes { /** diff --git a/telephony/common/com/google/android/mms/pdu/PduHeaders.java b/telephony/common/com/google/android/mms/pdu/PduHeaders.java index b5244645fda1..3e6218480dc5 100644 --- a/telephony/common/com/google/android/mms/pdu/PduHeaders.java +++ b/telephony/common/com/google/android/mms/pdu/PduHeaders.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java index f48399410723..5340245ae869 100755 --- a/telephony/common/com/google/android/mms/pdu/PduParser.java +++ b/telephony/common/com/google/android/mms/pdu/PduParser.java @@ -17,10 +17,9 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import com.google.android.mms.ContentType; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/PduPart.java b/telephony/common/com/google/android/mms/pdu/PduPart.java index 09b775118dc3..8dd976b2569f 100644 --- a/telephony/common/com/google/android/mms/pdu/PduPart.java +++ b/telephony/common/com/google/android/mms/pdu/PduPart.java @@ -17,10 +17,9 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.HashMap; import java.util.Map; diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java index b237705274da..fcd5b8ff57a8 100755 --- a/telephony/common/com/google/android/mms/pdu/PduPersister.java +++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java @@ -17,6 +17,7 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; @@ -34,13 +35,12 @@ import android.provider.Telephony.MmsSms; import android.provider.Telephony.MmsSms.PendingMessages; import android.provider.Telephony.Threads; import android.telephony.PhoneNumberUtils; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import com.google.android.mms.ContentType; import com.google.android.mms.InvalidHeaderValueException; import com.google.android.mms.MmsException; @@ -1448,9 +1448,9 @@ public class PduPersister { final Set<String> myPhoneNumbers = new HashSet<String>(); if (excludeMyNumber) { // Build a list of my phone numbers from the various sims. - for (int subid : subscriptionManager.getActiveSubscriptionIdList()) { + for (SubscriptionInfo subInfo : subscriptionManager.getActiveSubscriptionInfoList()) { final String myNumber = mContext.getSystemService(TelephonyManager.class). - createForSubscriptionId(subid).getLine1Number(); + createForSubscriptionId(subInfo.getSubscriptionId()).getLine1Number(); if (myNumber != null) { myPhoneNumbers.add(myNumber); } diff --git a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java index 9d6535c72e90..4e1d7f5775ec 100644 --- a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java +++ b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.ByteArrayOutputStream; diff --git a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java index e38c62dde622..4ba3c71580e0 100644 --- a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java +++ b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java index 9696bc259d00..37ccfb9c9b9b 100644 --- a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java +++ b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java index 03755af4189c..260adfc093f2 100644 --- a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java +++ b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/SendConf.java b/telephony/common/com/google/android/mms/pdu/SendConf.java index b85982791ada..779923801bfa 100644 --- a/telephony/common/com/google/android/mms/pdu/SendConf.java +++ b/telephony/common/com/google/android/mms/pdu/SendConf.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/SendReq.java b/telephony/common/com/google/android/mms/pdu/SendReq.java index c1b7f934c0f7..6e2f2da01791 100644 --- a/telephony/common/com/google/android/mms/pdu/SendReq.java +++ b/telephony/common/com/google/android/mms/pdu/SendReq.java @@ -17,10 +17,9 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import com.google.android.mms.InvalidHeaderValueException; public class SendReq extends MultimediaMessagePdu { diff --git a/telephony/common/com/google/android/mms/util/AbstractCache.java b/telephony/common/com/google/android/mms/util/AbstractCache.java index ab5d48a4ce3d..25862e73581e 100644 --- a/telephony/common/com/google/android/mms/util/AbstractCache.java +++ b/telephony/common/com/google/android/mms/util/AbstractCache.java @@ -17,10 +17,9 @@ package com.google.android.mms.util; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.HashMap; public abstract class AbstractCache<K, V> { diff --git a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java index 118de465a518..0f9390daa725 100644 --- a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java +++ b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java @@ -17,12 +17,11 @@ package com.google.android.mms.util; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.drm.DrmManagerClient; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - public class DownloadDrmHelper { private static final String TAG = "DownloadDrmHelper"; diff --git a/telephony/common/com/google/android/mms/util/DrmConvertSession.java b/telephony/common/com/google/android/mms/util/DrmConvertSession.java index 0e8ec91f4ef6..156c7ad8baac 100644 --- a/telephony/common/com/google/android/mms/util/DrmConvertSession.java +++ b/telephony/common/com/google/android/mms/util/DrmConvertSession.java @@ -16,14 +16,13 @@ */ package com.google.android.mms.util; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.drm.DrmConvertedStatus; import android.drm.DrmManagerClient; import android.provider.Downloads; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; diff --git a/telephony/common/com/google/android/mms/util/PduCache.java b/telephony/common/com/google/android/mms/util/PduCache.java index 94e38946f632..c380d6b3e30f 100644 --- a/telephony/common/com/google/android/mms/util/PduCache.java +++ b/telephony/common/com/google/android/mms/util/PduCache.java @@ -17,14 +17,13 @@ package com.google.android.mms.util; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentUris; import android.content.UriMatcher; import android.net.Uri; import android.provider.Telephony.Mms; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.HashMap; import java.util.HashSet; diff --git a/telephony/common/com/google/android/mms/util/PduCacheEntry.java b/telephony/common/com/google/android/mms/util/PduCacheEntry.java index 1ecd1bf93e7f..a4a25d2471ff 100644 --- a/telephony/common/com/google/android/mms/util/PduCacheEntry.java +++ b/telephony/common/com/google/android/mms/util/PduCacheEntry.java @@ -17,7 +17,7 @@ package com.google.android.mms.util; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.pdu.GenericPdu; diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java index 2dd1dc11c2a9..31fe4d7683d6 100644 --- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java +++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java @@ -18,6 +18,7 @@ package com.google.android.mms.util; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; @@ -27,8 +28,6 @@ import android.net.Uri; import android.util.Log; import android.widget.Toast; -import dalvik.annotation.compat.UnsupportedAppUsage; - public final class SqliteWrapper { private static final String TAG = "SqliteWrapper"; private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE diff --git a/telephony/java/android/service/carrier/CarrierIdentifier.java b/telephony/java/android/service/carrier/CarrierIdentifier.java index af5bf7475f95..7957c258b54f 100644 --- a/telephony/java/android/service/carrier/CarrierIdentifier.java +++ b/telephony/java/android/service/carrier/CarrierIdentifier.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.telephony.TelephonyManager; import com.android.internal.telephony.uicc.IccUtils; diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java index 6c357ccdd03d..8450a9018634 100644 --- a/telephony/java/android/service/euicc/EuiccProfileInfo.java +++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java @@ -19,7 +19,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.service.carrier.CarrierIdentifier; diff --git a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java index c7a985160730..2382f657c9ee 100644 --- a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java +++ b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java @@ -17,7 +17,7 @@ package android.service.euicc; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.telephony.euicc.DownloadableSubscription; diff --git a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java index abd4065c754a..d0fb51180c1d 100644 --- a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java +++ b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java @@ -17,7 +17,7 @@ package android.service.euicc; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.telephony.euicc.DownloadableSubscription; diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java index bb28df2b64eb..d325cd84855c 100644 --- a/telephony/java/android/telephony/AccessNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -50,18 +50,12 @@ public final class AccessNetworkConstants { /** * Transport type for Wireless Wide Area Networks (i.e. Cellular) - * @hide */ - @SystemApi - @TestApi public static final int TRANSPORT_TYPE_WWAN = 1; /** * Transport type for Wireless Local Area Networks (i.e. Wifi) - * @hide */ - @SystemApi - @TestApi public static final int TRANSPORT_TYPE_WLAN = 2; /** @hide */ diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index 7482ecc85324..9e6dfef0608b 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -596,4 +596,17 @@ public class Annotation { @Retention(RetentionPolicy.SOURCE) public @interface ImsAudioCodec { } + + /** + * UICC SIM Application Types + */ + @IntDef(prefix = { "APPTYPE_" }, value = { + TelephonyManager.APPTYPE_SIM, + TelephonyManager.APPTYPE_USIM, + TelephonyManager.APPTYPE_RUIM, + TelephonyManager.APPTYPE_CSIM, + TelephonyManager.APPTYPE_ISIM + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UiccAppType{} } diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java index 9753d8be4065..097041f672ac 100644 --- a/telephony/java/android/telephony/AnomalyReporter.java +++ b/telephony/java/android/telephony/AnomalyReporter.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.content.Context; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 77994420d83a..71aaa6e95352 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -24,7 +24,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.os.PersistableBundle; @@ -35,6 +35,7 @@ import android.telecom.TelecomManager; import android.telephony.ims.ImsReasonInfo; import com.android.internal.telephony.ICarrierConfigLoader; +import com.android.telephony.Rlog; /** * Provides access to telephony configuration values that are carrier-specific. @@ -299,7 +300,6 @@ public class CarrierConfigManager { /** * A string array containing numbers that shouldn't be included in the call log. - * @hide */ public static final String KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY = "unloggable_numbers_string_array"; @@ -312,12 +312,11 @@ public class CarrierConfigManager { KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool"; /** - * Do only allow auto selection in Advanced Network Settings when in home network. + * Only allow auto selection in Advanced Network Settings when in home network. * Manual selection is allowed when in roaming network. - * @hide */ - public static final String - KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network"; + public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = + "only_auto_select_in_home_network"; /** * Control whether users receive a simplified network settings UI and improved network @@ -581,9 +580,6 @@ public class CarrierConfigManager { * registration state to change. That is, turning on or off mobile data will not cause VT to be * enabled or disabled. * When {@code false}, disabling mobile data will cause VT to be de-registered. - * <p> - * See also {@link #KEY_VILTE_DATA_IS_METERED_BOOL}. - * @hide */ public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = "ignore_data_enabled_changed_for_video_calls"; @@ -647,7 +643,6 @@ public class CarrierConfigManager { /** * Default WFC_IMS_enabled: true VoWiFi by default is on * false VoWiFi by default is off - * @hide */ public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL = "carrier_default_wfc_ims_enabled_bool"; @@ -671,6 +666,12 @@ public class CarrierConfigManager { "carrier_promote_wfc_on_call_fail_bool"; /** + * Flag specifying whether provisioning is required for RCS. + */ + public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = + "carrier_rcs_provisioning_required_bool"; + + /** * Flag specifying whether provisioning is required for VoLTE, Video Telephony, and WiFi * Calling. */ @@ -713,9 +714,7 @@ public class CarrierConfigManager { * * As of now, Verizon is the only carrier enforcing this dependency in their * WFC awareness and activation requirements. - * - * @hide - * */ + */ public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool"; @@ -847,9 +846,12 @@ public class CarrierConfigManager { "carrier_force_disable_etws_cmas_test_bool"; /** - * The default flag specifying whether "Turn on Notifications" option will be always shown in - * Settings->More->Emergency broadcasts menu regardless developer options is turned on or not. + * The default flag specifying whether "Allow alerts" option will be always shown in + * emergency alerts settings regardless developer options is turned on or not. + * + * @deprecated The allow alerts option is always shown now. No longer need a config for that. */ + @Deprecated public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool"; @@ -1073,10 +1075,6 @@ public class CarrierConfigManager { * * When {@code false}, the old behavior is used, where the toggle in accessibility settings is * used to set the IMS stack's RTT enabled state. - * - * @deprecated -- this flag no longer does anything. Remove once the new behavior is verified. - * - * @hide */ public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool"; @@ -1125,7 +1123,6 @@ public class CarrierConfigManager { * Determines whether the IMS conference merge process supports and returns its participants * data. When {@code true}, on merge complete, conference call would have a list of its * participants returned in XML format, {@code false otherwise}. - * @hide */ public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL = "support_ims_conference_event_package_bool"; @@ -1198,20 +1195,18 @@ public class CarrierConfigManager { public static final String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array"; /** - * Determine whether user can switch Wi-Fi preferred or Cellular preferred in calling preference. + * Determine whether user can switch Wi-Fi preferred or Cellular preferred + * in calling preference. * Some operators support Wi-Fi Calling only, not VoLTE. * They don't need "Cellular preferred" option. - * In this case, set uneditalbe attribute for preferred preference. - * @hide + * In this case, set uneditable attribute for preferred preference. */ public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool"; - /** - * Flag to indicate if Wi-Fi needs to be disabled in ECBM - * @hide - **/ - public static final String - KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm"; + /** + * Flag to indicate if Wi-Fi needs to be disabled in ECBM. + */ + public static final String KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm"; /** * List operator-specific error codes and indices of corresponding error strings in @@ -1275,9 +1270,8 @@ public class CarrierConfigManager { public static final String KEY_WFC_SPN_USE_ROOT_LOCALE = "wfc_spn_use_root_locale"; /** - * The Component Name of the activity that can setup the emergency addrees for WiFi Calling + * The Component Name of the activity that can setup the emergency address for WiFi Calling * as per carrier requirement. - * @hide */ public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string"; @@ -1441,22 +1435,19 @@ public class CarrierConfigManager { public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool"; /** - * APN types that user is not allowed to modify - * @hide + * APN types that user is not allowed to modify. */ public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array"; /** - * APN fields that user is not allowed to modify - * @hide + * APN fields that user is not allowed to modify. */ public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array"; /** * Default value of APN types field if not specified by user when adding/modifying an APN. - * @hide */ public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array"; @@ -1487,29 +1478,25 @@ public class CarrierConfigManager { "hide_digits_helper_text_on_stk_input_screen_bool"; /** - * Boolean indicating if show data RAT icon on status bar even when data is disabled - * @hide + * Boolean indicating if show data RAT icon on status bar even when data is disabled. */ public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL = "always_show_data_rat_icon_bool"; /** - * Boolean indicating if default data account should show LTE or 4G icon - * @hide + * Boolean indicating if default data account should show LTE or 4G icon. */ public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; /** * Boolean indicating if default data account should show 4G icon when in 3G. - * @hide */ public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; /** - * Boolean indicating if lte+ icon should be shown if available - * @hide + * Boolean indicating if LTE+ icon should be shown if available. */ public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool"; @@ -1524,10 +1511,8 @@ public class CarrierConfigManager { "operator_name_filter_pattern_string"; /** - * The string is used to compare with operator name. If it matches the pattern then show - * specific data icon. - * - * @hide + * The string is used to compare with operator name. + * If it matches the pattern then show specific data icon. */ public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string"; @@ -1540,33 +1525,28 @@ public class CarrierConfigManager { "show_precise_failed_cause_bool"; /** - * Boolean to decide whether lte is enabled. - * @hide + * Boolean to decide whether LTE is enabled. */ public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool"; /** * Boolean to decide whether TD-SCDMA is supported. - * @hide */ public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool"; /** * A list of mcc/mnc that support TD-SCDMA for device when connect to the roaming network. - * @hide */ public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = "support_tdscdma_roaming_networks_string_array"; /** * Boolean to decide whether world mode is enabled. - * @hide */ public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool"; /** * Flatten {@link android.content.ComponentName} of the carrier's settings activity. - * @hide */ public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; @@ -1604,7 +1584,10 @@ public class CarrierConfigManager { public static final String KEY_MMS_UA_PROF_TAG_NAME_STRING = "uaProfTagName"; public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl"; public static final String KEY_MMS_USER_AGENT_STRING = "userAgent"; - /** @hide */ + /** + * If true, add "Connection: close" header to MMS HTTP requests so the connection + * is immediately closed (disabling keep-alive). + */ public static final String KEY_MMS_CLOSE_CONNECTION_BOOL = "mmsCloseConnection"; /** @@ -1620,25 +1603,23 @@ public class CarrierConfigManager { /** * Defines carrier-specific actions which act upon * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the - * default carrier app + * default carrier app. * Format: "CARRIER_ACTION_IDX, ..." * Where {@code CARRIER_ACTION_IDX} is an integer defined in - * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} + * com.android.carrierdefaultapp.CarrierActionUtils * Example: - * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS - * disable_metered_apns} - * @hide + * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS + * disables metered APNs */ - @UnsupportedAppUsage + @SuppressLint("IntentName") public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY = "carrier_default_actions_on_redirection_string_array"; /** - * Defines carrier-specific actions which act upon - * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED + * Defines carrier-specific actions which act upon CARRIER_SIGNAL_REQUEST_NETWORK_FAILED * and configured signal args: - * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType}, - * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode} + * android.telephony.TelephonyManager#EXTRA_APN_TYPE, + * android.telephony.TelephonyManager#EXTRA_ERROR_CODE * used for customization of the default carrier app * Format: * { @@ -1646,42 +1627,41 @@ public class CarrierConfigManager { * "APN_1, ERROR_CODE_2 : CARRIER_ACTION_IDX_1 " * } * Where {@code APN_1} is a string defined in - * {@link com.android.internal.telephony.PhoneConstants PhoneConstants} + * com.android.internal.telephony.PhoneConstants * Example: "default" * - * {@code ERROR_CODE_1} is an integer defined in - * {@link DataFailCause DcFailure} + * {@code ERROR_CODE_1} is an integer defined in android.telephony.DataFailCause * Example: - * {@link DataFailCause#MISSING_UNKNOWN_APN} + * android.telephony.DataFailCause#MISSING_UNKNOWN_APN * * {@code CARRIER_ACTION_IDX_1} is an integer defined in - * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} + * com.android.carrierdefaultapp.CarrierActionUtils * Example: - * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS} - * @hide + * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS + * disables metered APNs */ + @SuppressLint("IntentName") public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY = "carrier_default_actions_on_dcfailure_string_array"; /** - * Defines carrier-specific actions which act upon - * com.android.internal.telephony.CARRIER_SIGNAL_RESET, used for customization of the - * default carrier app + * Defines carrier-specific actions which act upon CARRIER_SIGNAL_RESET, + * used for customization of the default carrier app. * Format: "CARRIER_ACTION_IDX, ..." * Where {@code CARRIER_ACTION_IDX} is an integer defined in - * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} + * com.android.carrierdefaultapp.CarrierActionUtils * Example: - * {@link com.android.carrierdefaultapp.CarrierActionUtils - * #CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS clear all notifications on reset} - * @hide + * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS + * clears all notifications on reset */ + @SuppressLint("IntentName") public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET = "carrier_default_actions_on_reset_string_array"; /** * Defines carrier-specific actions which act upon * com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE, - * used for customization of the default carrier app + * used for customization of the default carrier app. * Format: * { * "true : CARRIER_ACTION_IDX_1", @@ -1689,17 +1669,17 @@ public class CarrierConfigManager { * } * Where {@code true} is a boolean indicates default network available/unavailable * Where {@code CARRIER_ACTION_IDX} is an integer defined in - * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} + * com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils * Example: - * {@link com.android.carrierdefaultapp.CarrierActionUtils - * #CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER enable the app as the default URL handler} - * @hide + * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER + * enables the app as the default URL handler */ + @SuppressLint("IntentName") public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE = "carrier_default_actions_on_default_network_available_string_array"; + /** - * Defines a list of acceptable redirection url for default carrier app - * @hides + * Defines a list of acceptable redirection url for default carrier app. */ public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY = "carrier_default_redirection_url_string_array"; @@ -1827,10 +1807,10 @@ public class CarrierConfigManager { /** * Determines whether to enable enhanced call blocking feature on the device. - * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED - * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE - * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE - * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN + * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED + * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE + * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE + * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN * * <p> * 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml @@ -1840,7 +1820,6 @@ public class CarrierConfigManager { * function is used regardless of SIM. * <p> * If {@code true} enable enhanced call blocking feature on the device, {@code false} otherwise. - * @hide */ public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = "support_enhanced_call_blocking_bool"; @@ -1943,7 +1922,6 @@ public class CarrierConfigManager { /** * Flag indicating whether the carrier supports call deflection for an incoming IMS call. - * @hide */ public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool"; @@ -2008,8 +1986,6 @@ public class CarrierConfigManager { /** * Whether system apps are allowed to use fallback if carrier video call is not available. * Defaults to {@code true}. - * - * @hide */ public static final String KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL = "allow_video_calling_fallback_bool"; @@ -2047,9 +2023,8 @@ public class CarrierConfigManager { "enhanced_4g_lte_title_variant_bool"; /** - * The index indicates the carrier specified title string of Enahnce 4G LTE Mode settings. + * The index indicates the carrier specified title string of Enhanced 4G LTE Mode settings. * Default value is 0, which indicates the default title string. - * @hide */ public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int"; @@ -2093,15 +2068,13 @@ public class CarrierConfigManager { * {@link #KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL} is false. If * {@link #KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL} is true, this * configuration is ignored and roaming preference cannot be changed. - * @hide */ public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool"; /** - * Flag specifying wether to show blocking pay phone option in blocked numbers screen. Only show - * the option if payphone call presentation represents in the carrier's region. - * @hide + * Flag specifying whether to show blocking pay phone option in blocked numbers screen. + * Only show the option if payphone call presentation is present in the carrier's region. */ public static final java.lang.String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool"; @@ -2111,7 +2084,6 @@ public class CarrierConfigManager { * {@code false} - roaming preference can be selected separately from the home preference. * {@code true} - roaming preference is the same as home preference and * {@link #KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} is used as the default value. - * @hide */ public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool"; @@ -2145,7 +2117,6 @@ public class CarrierConfigManager { * while the device is registered over WFC. Default value is -1, which indicates * that this notification is not pertinent for a particular carrier. We've added a delay * to prevent false positives. - * @hide */ public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int"; @@ -2196,7 +2167,6 @@ public class CarrierConfigManager { /** * Flag specifying whether to show an alert dialog for video call charges. * By default this value is {@code false}. - * @hide */ public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL = "show_video_call_charges_alert_dialog_bool"; @@ -2483,10 +2453,9 @@ public class CarrierConfigManager { /** * Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask. * 0 indicates that neither EPDG or WLAN is enabled. - * 1 indicates that key type {@link TelephonyManager#KEY_TYPE_EPDG} is enabled. - * 2 indicates that key type {@link TelephonyManager#KEY_TYPE_WLAN} is enabled. + * 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled. + * 2 indicates that key type TelephonyManager#KEY_TYPE_WLAN is enabled. * 3 indicates that both are enabled. - * @hide */ public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int"; @@ -2505,7 +2474,6 @@ public class CarrierConfigManager { /** * Flag specifying whether IMS registration state menu is shown in Status Info setting, * default to false. - * @hide */ public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool"; @@ -2561,7 +2529,6 @@ public class CarrierConfigManager { /** * The flag to disable the popup dialog which warns the user of data charges. - * @hide */ public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool"; @@ -2626,15 +2593,13 @@ public class CarrierConfigManager { /** * Determines whether any carrier has been identified and its specific config has been applied, * default to false. - * @hide */ public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool"; /** * Determines whether we should show a warning asking the user to check with their carrier - * on pricing when the user enabled data roaming. + * on pricing when the user enabled data roaming, * default to false. - * @hide */ public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool"; @@ -2786,10 +2751,10 @@ public class CarrierConfigManager { * Specifies a carrier-defined {@link android.telecom.CallRedirectionService} which Telecom * will bind to for outgoing calls. An empty string indicates that no carrier-defined * {@link android.telecom.CallRedirectionService} is specified. - * @hide */ public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string"; + /** * Support for the original string display of CDMA MO call. * By default, it is disabled. @@ -2902,8 +2867,8 @@ public class CarrierConfigManager { "call_waiting_service_class_int"; /** - * This configuration allow the system UI to display different 5G icon for different 5G - * scenario. + * This configuration allows the system UI to display different 5G icons for different 5G + * scenarios. * * There are five 5G scenarios: * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using @@ -2920,24 +2885,22 @@ public class CarrierConfigManager { * 5G cell as a secondary cell) but the use of 5G is restricted. * * The configured string contains multiple key-value pairs separated by comma. For each pair, - * the key and value is separated by a colon. The key is corresponded to a 5G status above and + * the key and value are separated by a colon. The key corresponds to a 5G status above and * the value is the icon name. Use "None" as the icon name if no icon should be shown in a * specific 5G scenario. If the scenario is "None", config can skip this key and value. * * Icon name options: "5G_Plus", "5G". * * Here is an example: - * UE want to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise no + * UE wants to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise not * define. * The configuration is: "connected_mmwave:5G_Plus,connected:5G" - * - * @hide */ public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string"; /** - * Timeout in second for displaying 5G icon, default value is 0 which means the timer is + * Timeout in seconds for displaying 5G icon, default value is 0 which means the timer is * disabled. * * System UI will show the 5G icon and start a timer with the timeout from this config when the @@ -2946,8 +2909,6 @@ public class CarrierConfigManager { * * If 5G is reacquired during this timer, the timer is canceled and restarted when 5G is next * lost. Allows us to momentarily lose 5G without blinking the icon. - * - * @hide */ public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int"; @@ -3026,6 +2987,13 @@ public class CarrierConfigManager { "ping_test_before_data_switch_bool"; /** + * Controls time in milliseconds until DcTracker reevaluates 5G connection state. + * @hide + */ + public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = + "5g_watchdog_time_long"; + + /** * Indicates zero or more emergency number prefix(es), because some carrier requires * if users dial an emergency number address with a specific prefix, the combination of the * prefix and the address is also a valid emergency number to dial. For example, an emergency @@ -3058,8 +3026,6 @@ public class CarrierConfigManager { * signal bar of primary network. By default it will be false, meaning whenever data * is going over opportunistic network, signal bar will reflect signal strength and rat * icon of that network. - * - * @hide */ public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN = "always_show_primary_signal_bar_in_opportunistic_network_boolean"; @@ -3153,7 +3119,6 @@ public class CarrierConfigManager { * 1 - yes. This is default. * @hide */ - // TODO(b/119567985): name this key properly public static final String KEY_SUPL_ES_STRING = KEY_PREFIX + "supl_es"; /** @@ -3273,8 +3238,6 @@ public class CarrierConfigManager { /** * Determines whether wifi calling location privacy policy is shown. - * - * @hide */ public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool"; @@ -3380,8 +3343,8 @@ public class CarrierConfigManager { "support_wps_over_ims_bool"; /** - * Holds the list of carrier certificate hashes. Note that each carrier has its own certificates - * @hide + * Holds the list of carrier certificate hashes. + * Note that each carrier has its own certificates. */ public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY = "carrier_certificate_string_array"; @@ -3439,6 +3402,7 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2); sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2); sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false); + sDefaults.putBoolean(KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL, true); sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, false); @@ -3564,7 +3528,7 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0); sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100); sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false); - sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, true); + sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false); sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0); sDefaults.putBoolean(KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true); @@ -3850,6 +3814,8 @@ public class CarrierConfigManager { /* Default value is 3 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000); sDefaults.putBoolean(KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL, true); + /* Default value is 1 hour. */ + sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000); sDefaults.putAll(Gps.getDefaults()); sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY, new int[] { @@ -3905,7 +3871,8 @@ public class CarrierConfigManager { + " ICarrierConfigLoader is null"); return null; } - return loader.getConfigForSubId(subId, mContext.getOpPackageName()); + return loader.getConfigForSubIdWithFeature(subId, mContext.getOpPackageName(), + null); } catch (RemoteException ex) { Rlog.e(TAG, "Error getting config for subId " + subId + ": " + ex.toString()); diff --git a/telephony/java/android/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java index 84be4e8b9ba4..719ba8d98773 100644 --- a/telephony/java/android/telephony/CbGeoUtils.java +++ b/telephony/java/android/telephony/CbGeoUtils.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.NonNull; import android.annotation.SystemApi; import android.text.TextUtils; diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index b7dab161c331..399b1a4f25de 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -16,13 +16,19 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.hardware.radio.V1_0.CellInfoType; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import com.android.telephony.Rlog; + import java.util.Objects; import java.util.UUID; @@ -181,7 +187,17 @@ public abstract class CellIdentity implements Parcelable { * @return a CellLocation object for this CellIdentity * @hide */ - public abstract CellLocation asCellLocation(); + @SystemApi + public abstract @NonNull CellLocation asCellLocation(); + + /** + * Create and a return a new instance of CellIdentity with location-identifying information + * removed. + * + * @hide + */ + @SystemApi + public abstract @NonNull CellIdentity sanitizeLocationInfo(); @Override public boolean equals(Object other) { @@ -310,4 +326,103 @@ public abstract class CellIdentity implements Parcelable { return true; } + /** @hide */ + public static CellIdentity create(android.hardware.radio.V1_0.CellIdentity cellIdentity) { + if (cellIdentity == null) return null; + switch(cellIdentity.cellInfoType) { + case CellInfoType.GSM: { + if (cellIdentity.cellIdentityGsm.size() == 1) { + return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0)); + } + break; + } + case CellInfoType.WCDMA: { + if (cellIdentity.cellIdentityWcdma.size() == 1) { + return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0)); + } + break; + } + case CellInfoType.TD_SCDMA: { + if (cellIdentity.cellIdentityTdscdma.size() == 1) { + return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0)); + } + break; + } + case CellInfoType.LTE: { + if (cellIdentity.cellIdentityLte.size() == 1) { + return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0)); + } + break; + } + case CellInfoType.CDMA: { + if (cellIdentity.cellIdentityCdma.size() == 1) { + return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0)); + } + break; + } + case CellInfoType.NONE: break; + default: break; + } + return null; + } + + /** @hide */ + public static CellIdentity create(android.hardware.radio.V1_2.CellIdentity cellIdentity) { + if (cellIdentity == null) return null; + switch(cellIdentity.cellInfoType) { + case CellInfoType.GSM: { + if (cellIdentity.cellIdentityGsm.size() == 1) { + return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0)); + } + break; + } + case CellInfoType.WCDMA: { + if (cellIdentity.cellIdentityWcdma.size() == 1) { + return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0)); + } + break; + } + case CellInfoType.TD_SCDMA: { + if (cellIdentity.cellIdentityTdscdma.size() == 1) { + return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0)); + } + break; + } + case CellInfoType.LTE: { + if (cellIdentity.cellIdentityLte.size() == 1) { + return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0)); + } + break; + } + case CellInfoType.CDMA: { + if (cellIdentity.cellIdentityCdma.size() == 1) { + return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0)); + } + break; + } + case CellInfoType.NONE: break; + default: break; + } + return null; + } + + /** @hide */ + public static CellIdentity create(android.hardware.radio.V1_5.CellIdentity ci) { + if (ci == null) return null; + switch (ci.getDiscriminator()) { + case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.gsm: + return new CellIdentityGsm(ci.gsm()); + case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.cdma: + return new CellIdentityCdma(ci.cdma()); + case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.lte: + return new CellIdentityLte(ci.lte()); + case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.wcdma: + return new CellIdentityWcdma(ci.wcdma()); + case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.tdscdma: + return new CellIdentityTdscdma(ci.tdscdma()); + case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.nr: + return new CellIdentityNr(ci.nr()); + default: return null; + } + } } diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index 880d3db681b5..1a6bf33cec71 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.os.Parcel; import android.telephony.cdma.CdmaCellLocation; @@ -127,7 +128,8 @@ public final class CellIdentityCdma extends CellIdentity { } /** @hide */ - public CellIdentityCdma sanitizeLocationInfo() { + @Override + public @NonNull CellIdentityCdma sanitizeLocationInfo() { return new CellIdentityCdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort); @@ -198,6 +200,7 @@ public final class CellIdentityCdma extends CellIdentity { } /** @hide */ + @NonNull @Override public CdmaCellLocation asCellLocation() { CdmaCellLocation cl = new CdmaCellLocation(); diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index 25c6577bdcf5..49f425acead6 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -16,8 +16,9 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; @@ -103,7 +104,8 @@ public final class CellIdentityGsm extends CellIdentity { } /** @hide */ - public CellIdentityGsm sanitizeLocationInfo() { + @Override + public @NonNull CellIdentityGsm sanitizeLocationInfo() { return new CellIdentityGsm(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr, mAlphaLong, mAlphaShort); } @@ -200,6 +202,7 @@ public final class CellIdentityGsm extends CellIdentity { } /** @hide */ + @NonNull @Override public GsmCellLocation asCellLocation() { GsmCellLocation cl = new GsmCellLocation(); diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 997b19f3d4eb..bc4655069dba 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -16,8 +16,9 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; @@ -120,7 +121,8 @@ public final class CellIdentityLte extends CellIdentity { } /** @hide */ - public CellIdentityLte sanitizeLocationInfo() { + @Override + public @NonNull CellIdentityLte sanitizeLocationInfo() { return new CellIdentityLte(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr, mAlphaLong, mAlphaShort); @@ -232,6 +234,7 @@ public final class CellIdentityLte extends CellIdentity { * * @hide */ + @NonNull @Override public GsmCellLocation asCellLocation() { GsmCellLocation cl = new GsmCellLocation(); diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java index edc838c163db..f08a5807c2b6 100644 --- a/telephony/java/android/telephony/CellIdentityNr.java +++ b/telephony/java/android/telephony/CellIdentityNr.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.IntRange; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; @@ -68,7 +69,8 @@ public final class CellIdentityNr extends CellIdentity { } /** @hide */ - public CellIdentityNr sanitizeLocationInfo() { + @Override + public @NonNull CellIdentityNr sanitizeLocationInfo() { return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort); } @@ -77,6 +79,7 @@ public final class CellIdentityNr extends CellIdentity { * @return a CellLocation object for this CellIdentity. * @hide */ + @NonNull @Override public CellLocation asCellLocation() { return new GsmCellLocation(); diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java index 558e346284ea..4bb3a95a9f1d 100644 --- a/telephony/java/android/telephony/CellIdentityTdscdma.java +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -97,7 +97,8 @@ public final class CellIdentityTdscdma extends CellIdentity { } /** @hide */ - public CellIdentityTdscdma sanitizeLocationInfo() { + @Override + public @NonNull CellIdentityTdscdma sanitizeLocationInfo() { return new CellIdentityTdscdma(mMccStr, mMncStr, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort); } @@ -171,6 +172,7 @@ public final class CellIdentityTdscdma extends CellIdentity { } /** @hide */ + @NonNull @Override public GsmCellLocation asCellLocation() { GsmCellLocation cl = new GsmCellLocation(); diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index 031fed13d9f1..4ecd134c4ba9 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -16,8 +16,9 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; @@ -97,7 +98,8 @@ public final class CellIdentityWcdma extends CellIdentity { } /** @hide */ - public CellIdentityWcdma sanitizeLocationInfo() { + @Override + public @NonNull CellIdentityWcdma sanitizeLocationInfo() { return new CellIdentityWcdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr, mAlphaLong, mAlphaShort); @@ -196,6 +198,7 @@ public final class CellIdentityWcdma extends CellIdentity { } /** @hide */ + @NonNull @Override public GsmCellLocation asCellLocation() { GsmCellLocation cl = new GsmCellLocation(); diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java index ae45307f19f0..ec86c144c08e 100644 --- a/telephony/java/android/telephony/CellInfo.java +++ b/telephony/java/android/telephony/CellInfo.java @@ -18,7 +18,8 @@ package android.telephony; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.annotation.SuppressLint; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.radio.V1_4.CellInfo.Info; import android.os.Parcel; import android.os.Parcelable; @@ -179,6 +180,18 @@ public abstract class CellInfo implements Parcelable { * * @return a time stamp in nanos since boot. */ + @SuppressLint("MethodNameUnits") + public long getTimestampNanos() { + return mTimeStamp; + } + + /** + * Approximate time this cell information was received from the modem. + * + * @return a time stamp in nanos since boot. + * @deprecated Use {@link #getTimestampNanos} instead. + */ + @Deprecated public long getTimeStamp() { return mTimeStamp; } diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java index 30b131faf51d..acb21f450243 100644 --- a/telephony/java/android/telephony/CellInfoCdma.java +++ b/telephony/java/android/telephony/CellInfoCdma.java @@ -16,12 +16,13 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Rlog; /** * A {@link CellInfo} representing a CDMA cell that provides identity and measurement info. diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java index 137f97eeee62..79a9d44f36a2 100644 --- a/telephony/java/android/telephony/CellInfoGsm.java +++ b/telephony/java/android/telephony/CellInfoGsm.java @@ -16,11 +16,12 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Rlog; /** * A {@link CellInfo} representing a GSM cell that provides identity and measurement info. diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java index da7b7ab1488d..fed3ebf4af03 100644 --- a/telephony/java/android/telephony/CellInfoLte.java +++ b/telephony/java/android/telephony/CellInfoLte.java @@ -16,8 +16,10 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java index f1305f5ca768..58ff8c9558d9 100644 --- a/telephony/java/android/telephony/CellInfoTdscdma.java +++ b/telephony/java/android/telephony/CellInfoTdscdma.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java index ee5fec838d2d..33f6a555414c 100644 --- a/telephony/java/android/telephony/CellInfoWcdma.java +++ b/telephony/java/android/telephony/CellInfoWcdma.java @@ -18,7 +18,7 @@ package android.telephony; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import java.util.Objects; diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java index 01331535205c..64776e377fa4 100644 --- a/telephony/java/android/telephony/CellLocation.java +++ b/telephony/java/android/telephony/CellLocation.java @@ -16,13 +16,13 @@ package android.telephony; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; - -import android.annotation.UnsupportedAppUsage; import android.telephony.cdma.CdmaCellLocation; import android.telephony.gsm.GsmCellLocation; + import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.PhoneConstants; diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java index 199843905854..cab3b0cd3c47 100644 --- a/telephony/java/android/telephony/CellSignalStrengthCdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java @@ -20,7 +20,7 @@ import android.annotation.IntRange; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import java.util.Objects; diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java index fb16d540fbb4..28052aa93486 100644 --- a/telephony/java/android/telephony/CellSignalStrengthGsm.java +++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java @@ -16,13 +16,14 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; -import android.telephony.Rlog; import java.util.Objects; diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index 8df9d23598eb..2ef2a52977ff 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -16,8 +16,10 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java index f31fafe36508..4d67bcf536cf 100644 --- a/telephony/java/android/telephony/CellSignalStrengthNr.java +++ b/telephony/java/android/telephony/CellSignalStrengthNr.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.IntDef; import android.annotation.IntRange; import android.os.Parcel; @@ -155,7 +157,17 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa * @param ss signal strength from modem. */ public CellSignalStrengthNr(android.hardware.radio.V1_4.NrSignalStrength ss) { - this(ss.csiRsrp, ss.csiRsrq, ss.csiSinr, ss.ssRsrp, ss.ssRsrq, ss.ssSinr); + this(flip(ss.csiRsrp), flip(ss.csiRsrq), ss.csiSinr, flip(ss.ssRsrp), flip(ss.ssRsrq), + ss.ssSinr); + } + + /** + * Flip sign cell strength value when taking in the value from hal + * @param val cell strength value + * @return flipped value + */ + private static int flip(int val) { + return val != CellInfo.UNAVAILABLE ? -val : val; } /** diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java index f4a3dbb37988..3bd9d5810136 100644 --- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.IntRange; import android.annotation.NonNull; import android.os.Parcel; diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java index 4dc54f0fef58..535e9520074d 100644 --- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java @@ -16,13 +16,14 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.IntRange; import android.annotation.StringDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; -import android.telephony.Rlog; import android.text.TextUtils; import java.lang.annotation.Retention; diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index 04ec4b6949af..aff1391fc080 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -18,7 +18,7 @@ package android.telephony; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Describes the cause of a disconnected call. Those disconnect causes can be converted into a more diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java index 39af34c0e0f0..9b4292f42172 100644 --- a/telephony/java/android/telephony/ImsManager.java +++ b/telephony/java/android/telephony/ImsManager.java @@ -17,6 +17,8 @@ package android.telephony.ims; import android.annotation.NonNull; +import android.annotation.SdkConstant; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -35,7 +37,63 @@ public class ImsManager { private Context mContext; - /** @hide */ + /** + * <p>Broadcast Action: Indicates that an IMS operation was rejected by the network due to it + * not being authorized on the network. + * May include the {@link SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX} extra to also specify + * which subscription the operation was rejected for. + * <p class="note"> + * Carrier applications may listen to this broadcast to be notified of possible IMS provisioning + * issues. + */ + // Moved from TelephonyIntents, need to keep backwards compatibility with OEM apps that have + // this value hard-coded in BroadcastReceiver. + @SuppressLint("ActionValue") + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = + "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION"; + + /** + * An intent action indicating that IMS registration for WiFi calling has resulted in an error. + * Contains error information that should be displayed to the user. + * <p> + * This intent will contain the following extra key/value pairs: + * {@link #EXTRA_WFC_REGISTRATION_FAILURE_TITLE} + * and {@link #EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE}, which contain carrier specific + * error information that should be displayed to the user. + * <p> + * Usage: This intent is sent as an ordered broadcast. If the settings application is going + * to show the error information specified to the user, it should respond to + * {@link android.content.BroadcastReceiver#setResultCode(int)} with + * {@link android.app.Activity#RESULT_CANCELED}, which will signal to the framework that the + * event was handled. If the framework does not receive a response to the ordered broadcast, + * it will then show a notification to the user indicating that there was a registration + * failure. + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = + "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; + + /** + * An extra key corresponding to a String value which contains the carrier specific title to be + * displayed as part of the message shown to the user when there is an error registering for + * WiFi calling. + */ + public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = + "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; + + /** + * An extra key corresponding to a String value which contains the carrier specific message to + * be displayed as part of the message shown to the user when there is an error registering for + * WiFi calling. + */ + public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = + "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; + + /** + * Use {@link Context#getSystemService(String)} to get an instance of this class. + * @hide + */ public ImsManager(@NonNull Context context) { mContext = context; } diff --git a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java index 92a674c57688..1c31368d8443 100644 --- a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java +++ b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java @@ -16,7 +16,7 @@ package android.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.text.Editable; /* diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java index 023ed305ef50..5f4679918998 100644 --- a/telephony/java/android/telephony/NeighboringCellInfo.java +++ b/telephony/java/android/telephony/NeighboringCellInfo.java @@ -24,7 +24,7 @@ import static android.telephony.TelephonyManager.NETWORK_TYPE_HSUPA; import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS; import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index fc717e7465b1..32ffb75f373c 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -36,23 +36,24 @@ import java.util.stream.Collectors; /** * Description of a mobile network registration info - * @hide */ -@SystemApi -@TestApi public final class NetworkRegistrationInfo implements Parcelable { /** * Network domain * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "DOMAIN_", value = {DOMAIN_CS, DOMAIN_PS}) + @IntDef(prefix = "DOMAIN_", value = {DOMAIN_UNKNOWN, DOMAIN_CS, DOMAIN_PS, DOMAIN_CS_PS}) public @interface Domain {} - /** Circuit switching domain */ - public static final int DOMAIN_CS = 1; - /** Packet switching domain */ - public static final int DOMAIN_PS = 2; + /** Unknown / Unspecified domain */ + public static final int DOMAIN_UNKNOWN = 0; + /** Circuit switched domain */ + public static final int DOMAIN_CS = android.hardware.radio.V1_5.Domain.CS; + /** Packet switched domain */ + public static final int DOMAIN_PS = android.hardware.radio.V1_5.Domain.PS; + /** Applicable to both CS and PS Domain */ + public static final int DOMAIN_CS_PS = DOMAIN_CS | DOMAIN_PS; /** * Network registration state @@ -65,17 +66,41 @@ public final class NetworkRegistrationInfo implements Parcelable { REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING}) public @interface RegistrationState {} - /** Not registered. The device is not currently searching a new operator to register. */ + /** + * Not registered. The device is not currently searching a new operator to register. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; - /** Registered on home network. */ + /** + * Registered on home network. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_HOME = 1; - /** Not registered. The device is currently searching a new operator to register. */ + /** + * Not registered. The device is currently searching a new operator to register. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; - /** Registration denied. */ + /** + * Registration denied. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_DENIED = 3; - /** Registration state is unknown. */ + /** + * Registration state is unknown. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_UNKNOWN = 4; - /** Registered on roaming network. */ + /** + * Registered on roaming network. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_ROAMING = 5; /** @hide */ @@ -88,7 +113,6 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * The device isn't camped on an LTE cell or the LTE cell doesn't support E-UTRA-NR * Dual Connectivity(EN-DC). - * @hide */ public static final int NR_STATE_NONE = 0; @@ -96,7 +120,6 @@ public final class NetworkRegistrationInfo implements Parcelable { * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but * either the use of dual connectivity with NR(DCNR) is restricted or NR is not supported by * the selected PLMN. - * @hide */ public static final int NR_STATE_RESTRICTED = 1; @@ -104,14 +127,12 @@ public final class NetworkRegistrationInfo implements Parcelable { * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and both * the use of dual connectivity with NR(DCNR) is not restricted and NR is supported by the * selected PLMN. - * @hide */ public static final int NR_STATE_NOT_RESTRICTED = 2; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and * also connected to at least one 5G cell as a secondary serving cell. - * @hide */ public static final int NR_STATE_CONNECTED = 3; @@ -125,22 +146,34 @@ public final class NetworkRegistrationInfo implements Parcelable { SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY}) public @interface ServiceType {} - /** Unkown service */ + /** + * Unknown service + */ public static final int SERVICE_TYPE_UNKNOWN = 0; - /** Voice service */ + /** + * Voice service + */ public static final int SERVICE_TYPE_VOICE = 1; - /** Data service */ + /** + * Data service + */ public static final int SERVICE_TYPE_DATA = 2; - /** SMS service */ + /** + * SMS service + */ public static final int SERVICE_TYPE_SMS = 3; - /** Video service */ + /** + * Video service + */ public static final int SERVICE_TYPE_VIDEO = 4; - /** Emergency service */ + /** + * Emergency service + */ public static final int SERVICE_TYPE_EMERGENCY = 5; @Domain @@ -326,9 +359,7 @@ public final class NetworkRegistrationInfo implements Parcelable { * Get the 5G NR connection state. * * @return the 5G NR connection state. - * @hide */ - @SystemApi public @NRState int getNrState() { return mNrState; } @@ -340,7 +371,10 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * @return The registration state. + * + * @hide */ + @SystemApi @TestApi public @RegistrationState int getRegistrationState() { return mRegistrationState; } @@ -348,6 +382,21 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * @return {@code true} if registered on roaming network, {@code false} otherwise. */ + public boolean isRegistered() { + return mRegistrationState == REGISTRATION_STATE_HOME + || mRegistrationState == REGISTRATION_STATE_ROAMING; + } + + /** + * @return {@code true} if registered on roaming network, {@code false} otherwise. + */ + public boolean isSearching() { + return mRegistrationState == REGISTRATION_STATE_NOT_REGISTERED_SEARCHING; + } + + /** + * @return {@code true} if registered on roaming network, {@code false} otherwise. + */ public boolean isRoaming() { return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING; } @@ -372,15 +421,18 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * @return the current network roaming type. + * @hide */ - + @SystemApi @TestApi public @ServiceState.RoamingType int getRoamingType() { return mRoamingType; } /** * @return Whether emergency is enabled. + * @hide */ + @SystemApi @TestApi public boolean isEmergencyEnabled() { return mEmergencyOnly; } /** @@ -418,7 +470,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * @return Reason for denial if the registration state is {@link #REGISTRATION_STATE_DENIED}. * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008 * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA + * @hide */ + @SystemApi @TestApi public int getRejectCause() { return mRejectCause; } @@ -441,8 +495,10 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * @return Data registration related info + * @hide */ @Nullable + @SystemApi @TestApi public DataSpecificRegistrationInfo getDataSpecificInfo() { return mDataSpecificInfo; } @@ -504,11 +560,21 @@ public final class NetworkRegistrationInfo implements Parcelable { } } + /** @hide */ + static @NonNull String domainToString(@Domain int domain) { + switch (domain) { + case DOMAIN_CS: return "CS"; + case DOMAIN_PS: return "PS"; + case DOMAIN_CS_PS: return "CS_PS"; + default: return "UNKNOWN"; + } + } + @NonNull @Override public String toString() { return new StringBuilder("NetworkRegistrationInfo{") - .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS") + .append(" domain=").append(domainToString(mDomain)) .append(" transportType=").append( AccessNetworkConstants.transportTypeToString(mTransportType)) .append(" registrationState=").append(registrationStateToString(mRegistrationState)) @@ -557,7 +623,11 @@ public final class NetworkRegistrationInfo implements Parcelable { && mNrState == other.mNrState; } + /** + * @hide + */ @Override + @SystemApi @TestApi public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mDomain); dest.writeInt(mTransportType); @@ -645,8 +715,10 @@ public final class NetworkRegistrationInfo implements Parcelable { * .setRegistrationState(REGISTRATION_STATE_HOME) * .build(); * </code></pre> + * @hide */ - public static final class Builder{ + @SystemApi @TestApi + public static final class Builder { @Domain private int mDomain; @@ -745,7 +817,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * @param emergencyOnly True if this network registration is for emergency use only. * * @return The same instance of the builder. + * @hide */ + @SystemApi @TestApi public @NonNull Builder setEmergencyOnly(boolean emergencyOnly) { mEmergencyOnly = emergencyOnly; return this; @@ -757,7 +831,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * @param availableServices Available services. * * @return The same instance of the builder. + * @hide */ + @SystemApi @TestApi public @NonNull Builder setAvailableServices( @NonNull @ServiceType List<Integer> availableServices) { mAvailableServices = availableServices; @@ -770,7 +846,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * @param cellIdentity The cell identity. * * @return The same instance of the builder. + * @hide */ + @SystemApi @TestApi public @NonNull Builder setCellIdentity(@Nullable CellIdentity cellIdentity) { mCellIdentity = cellIdentity; return this; @@ -778,9 +856,10 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * Build the NetworkRegistrationInfo. - * * @return the NetworkRegistrationInfo object. + * @hide */ + @SystemApi @TestApi public @NonNull NetworkRegistrationInfo build() { return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices, diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java index 202da6817cb5..c249ece92e73 100644 --- a/telephony/java/android/telephony/NetworkScan.java +++ b/telephony/java/android/telephony/NetworkScan.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.IntDef; import android.content.Context; import android.os.RemoteException; diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java index 8c5e10788b89..844289ce75d4 100644 --- a/telephony/java/android/telephony/NetworkService.java +++ b/telephony/java/android/telephony/NetworkService.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; diff --git a/telephony/java/android/telephony/NetworkServiceCallback.java b/telephony/java/android/telephony/NetworkServiceCallback.java index 89b96654451e..214ab41ae4f2 100644 --- a/telephony/java/android/telephony/NetworkServiceCallback.java +++ b/telephony/java/android/telephony/NetworkServiceCallback.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; diff --git a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java index ac6bcaa61997..d4ed860cdafd 100644 --- a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java +++ b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java @@ -16,15 +16,14 @@ package android.telephony; -import com.android.i18n.phonenumbers.AsYouTypeFormatter; -import com.android.i18n.phonenumbers.PhoneNumberUtil; - -import android.annotation.UnsupportedAppUsage; -import android.telephony.PhoneNumberUtils; +import android.compat.annotation.UnsupportedAppUsage; import android.text.Editable; import android.text.Selection; import android.text.TextWatcher; +import com.android.i18n.phonenumbers.AsYouTypeFormatter; +import com.android.i18n.phonenumbers.PhoneNumberUtil; + import java.util.Locale; /** diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 67afa7d3a3c9..0074772a221d 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -16,17 +16,18 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.database.Cursor; -import android.location.CountryDetector; import android.net.Uri; import android.os.PersistableBundle; import android.provider.Contacts; @@ -2030,6 +2031,7 @@ public class PhoneNumberUtils { private static boolean isEmergencyNumberInternal(int subId, String number, String defaultCountryIso, boolean useExactMatch) { + // TODO: clean up all the callers that pass in a defaultCountryIso, since it's ignored now. try { if (useExactMatch) { return TelephonyManager.getDefault().isEmergencyNumber(number); @@ -2191,18 +2193,7 @@ public class PhoneNumberUtils { private static boolean isLocalEmergencyNumberInternal(int subId, String number, Context context, boolean useExactMatch) { - String countryIso; - CountryDetector detector = (CountryDetector) context.getSystemService( - Context.COUNTRY_DETECTOR); - if (detector != null && detector.detectCountry() != null) { - countryIso = detector.detectCountry().getCountryIso(); - } else { - Locale locale = context.getResources().getConfiguration().locale; - countryIso = locale.getCountry(); - Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: " - + countryIso); - } - return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch); + return isEmergencyNumberInternal(subId, number, null /* unused */, useExactMatch); } /** diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java index bfa6326c3c18..98eeacf1a416 100644 --- a/telephony/java/android/telephony/PreciseCallState.java +++ b/telephony/java/android/telephony/PreciseCallState.java @@ -19,14 +19,12 @@ package android.telephony; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.DisconnectCauses; import android.telephony.Annotation.PreciseCallStates; import android.telephony.Annotation.PreciseDisconnectCauses; -import android.telephony.DisconnectCause; -import android.telephony.PreciseDisconnectCause; import java.util.Objects; diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index 78ad5c58423c..31434c1d2adf 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.LinkProperties; import android.os.Build; import android.os.Parcel; @@ -81,18 +81,20 @@ public final class PreciseDataConnectionState implements Parcelable { /** - * Constructor + * Constructor of PreciseDataConnectionState * * @param state the state of the data connection * @param networkType the access network that is/would carry this data connection * @param apnTypes the APN types that this data connection carries - * @param apnSetting if there is a valid APN for this Data Connection, then the APN Settings; - * if there is no valid APN setting for the specific type, then this will be null + * @param apn the APN of this data connection * @param linkProperties if the data connection is connected, the properties of the connection * @param failCause in case a procedure related to this data connection fails, a non-zero error * code indicating the cause of the failure. + * @param apnSetting if there is a valid APN for this Data Connection, then the APN Settings; + * if there is no valid APN setting for the specific type, then this will be null * @hide */ + @SystemApi public PreciseDataConnectionState(@DataState int state, @NetworkType int networkType, @ApnType int apnTypes, @NonNull String apn, diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java index 28f6515d09e5..bc8473865466 100644 --- a/telephony/java/android/telephony/RadioAccessFamily.java +++ b/telephony/java/android/telephony/RadioAccessFamily.java @@ -16,9 +16,7 @@ package android.telephony; -import android.annotation.UnsupportedAppUsage; -import android.hardware.radio.V1_0.RadioTechnology; -import android.hardware.radio.V1_4.CellInfo.Info; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 1014571bc41a..ed003ed81ddc 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Build; import android.os.Bundle; @@ -34,6 +34,8 @@ import android.telephony.NetworkRegistrationInfo.Domain; import android.telephony.NetworkRegistrationInfo.NRState; import android.text.TextUtils; +import com.android.telephony.Rlog; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -64,6 +66,13 @@ public class ServiceState implements Parcelable { static final boolean DBG = false; static final boolean VDBG = false; // STOPSHIP if true + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "STATE_", + value = {STATE_IN_SERVICE, STATE_OUT_OF_SERVICE, STATE_EMERGENCY_ONLY, + STATE_POWER_OFF}) + public @interface RegState {} + /** * Normal operation condition, the phone is registered * with an operator either in home network or in roaming. @@ -82,6 +91,7 @@ public class ServiceState implements Parcelable { /** * The phone is registered and locked. Only emergency numbers are allowed. {@more} */ + //TODO: This state is not used anymore. It should be deprecated in a future release. public static final int STATE_EMERGENCY_ONLY = TelephonyProtoEnums.SERVICE_STATE_EMERGENCY_ONLY; // 2 @@ -371,15 +381,15 @@ public class ServiceState implements Parcelable { /** * Create a new ServiceState from a intent notifier Bundle * - * This method is used by PhoneStateIntentReceiver, CellBroadcastReceiver, and maybe by - * external applications. + * This method is used to get ServiceState object from extras upon receiving + * {@link Intent#ACTION_SERVICE_STATE}. * * @param m Bundle from intent notifier * @return newly created ServiceState * @hide */ + @SystemApi @NonNull - @UnsupportedAppUsage public static ServiceState newFromBundle(@NonNull Bundle m) { ServiceState ret; ret = new ServiceState(); @@ -530,13 +540,15 @@ public class ServiceState implements Parcelable { } /** - * Get current data service state + * Get current data registration state. * * @see #STATE_IN_SERVICE * @see #STATE_OUT_OF_SERVICE * @see #STATE_EMERGENCY_ONLY * @see #STATE_POWER_OFF * + * @return current data registration state + * * @hide */ @UnsupportedAppUsage @@ -545,6 +557,23 @@ public class ServiceState implements Parcelable { } /** + * Get current data registration state. + * + * @see #STATE_IN_SERVICE + * @see #STATE_OUT_OF_SERVICE + * @see #STATE_EMERGENCY_ONLY + * @see #STATE_POWER_OFF + * + * @return current data registration state + * + * @hide + */ + @SystemApi + public @RegState int getDataRegistrationState() { + return getDataRegState(); + } + + /** * Get the current duplex mode * * @see #DUPLEX_MODE_UNKNOWN @@ -555,8 +584,8 @@ public class ServiceState implements Parcelable { */ @DuplexMode public int getDuplexMode() { - // only support LTE duplex mode - if (!isLte(getRilDataRadioTechnology())) { + // support LTE/NR duplex mode + if (!isPsOnlyTech(getRilDataRadioTechnology())) { return DUPLEX_MODE_UNKNOWN; } @@ -1254,11 +1283,15 @@ public class ServiceState implements Parcelable { /** * Set intent notifier Bundle based on service state. * + * Put ServiceState object and its fields into bundle which is used by TelephonyRegistry + * to broadcast {@link Intent#ACTION_SERVICE_STATE}. + * * @param m intent notifier Bundle * @hide + * */ - @UnsupportedAppUsage - public void fillInNotifierBundle(Bundle m) { + @SystemApi + public void fillInNotifierBundle(@NonNull Bundle m) { m.putParcelable(Intent.EXTRA_SERVICE_STATE, this); // serviceState already consists of below entries. // for backward compatibility, we continue fill in below entries. @@ -1437,7 +1470,15 @@ public class ServiceState implements Parcelable { return getRilDataRadioTechnology(); } - /** @hide */ + /** + * Transform RIL radio technology {@link RilRadioTechnology} value to Network + * type {@link NetworkType}. + * + * @param rat The RIL radio technology {@link RilRadioTechnology}. + * @return The network type {@link NetworkType}. + * + * @hide + */ public static int rilRadioTechnologyToNetworkType(@RilRadioTechnology int rat) { switch(rat) { case RIL_RADIO_TECHNOLOGY_GPRS: @@ -1519,7 +1560,15 @@ public class ServiceState implements Parcelable { } } - /** @hide */ + /** + * Transform network type {@link NetworkType} value to RIL radio technology + * {@link RilRadioTechnology}. + * + * @param networkType The network type {@link NetworkType}. + * @return The RIL radio technology {@link RilRadioTechnology}. + * + * @hide + */ public static int networkTypeToRilRadioTechnology(int networkType) { switch(networkType) { case TelephonyManager.NETWORK_TYPE_GPRS: @@ -1575,7 +1624,8 @@ public class ServiceState implements Parcelable { * @return Current data network type * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @SystemApi + @TestApi public @NetworkType int getDataNetworkType() { final NetworkRegistrationInfo iwlanRegInfo = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); @@ -1668,9 +1718,10 @@ public class ServiceState implements Parcelable { } /** @hide */ - public static boolean isLte(int radioTechnology) { - return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE || - radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA; + public static boolean isPsOnlyTech(int radioTechnology) { + return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE + || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA + || radioTechnology == RIL_RADIO_TECHNOLOGY_NR; } /** @hide */ @@ -1720,7 +1771,14 @@ public class ServiceState implements Parcelable { return bearerBitmask; } - /** @hide */ + /** + * Convert network type bitmask to bearer bitmask. + * + * @param networkTypeBitmask The network type bitmask value + * @return The bearer bitmask value. + * + * @hide + */ public static int convertNetworkTypeBitmaskToBearerBitmask(int networkTypeBitmask) { if (networkTypeBitmask == 0) { return 0; @@ -1734,7 +1792,14 @@ public class ServiceState implements Parcelable { return bearerBitmask; } - /** @hide */ + /** + * Convert bearer bitmask to network type bitmask. + * + * @param bearerBitmask The bearer bitmask value. + * @return The network type bitmask value. + * + * @hide + */ public static int convertBearerBitmaskToNetworkTypeBitmask(int bearerBitmask) { if (bearerBitmask == 0) { return 0; @@ -1772,10 +1837,8 @@ public class ServiceState implements Parcelable { * Get all of the available network registration info. * * @return List of {@link NetworkRegistrationInfo} - * @hide */ @NonNull - @SystemApi public List<NetworkRegistrationInfo> getNetworkRegistrationInfoList() { synchronized (mNetworkRegistrationInfos) { List<NetworkRegistrationInfo> newList = new ArrayList<>(); @@ -1825,7 +1888,7 @@ public class ServiceState implements Parcelable { synchronized (mNetworkRegistrationInfos) { for (NetworkRegistrationInfo networkRegistrationInfo : mNetworkRegistrationInfos) { - if (networkRegistrationInfo.getDomain() == domain) { + if ((networkRegistrationInfo.getDomain() & domain) != 0) { list.add(new NetworkRegistrationInfo(networkRegistrationInfo)); } } @@ -1841,7 +1904,6 @@ public class ServiceState implements Parcelable { * @param transportType The transport type * @return The matching {@link NetworkRegistrationInfo} * @hide - * */ @Nullable @SystemApi @@ -1850,7 +1912,7 @@ public class ServiceState implements Parcelable { synchronized (mNetworkRegistrationInfos) { for (NetworkRegistrationInfo networkRegistrationInfo : mNetworkRegistrationInfos) { if (networkRegistrationInfo.getTransportType() == transportType - && networkRegistrationInfo.getDomain() == domain) { + && (networkRegistrationInfo.getDomain() & domain) != 0) { return new NetworkRegistrationInfo(networkRegistrationInfo); } } @@ -1893,9 +1955,18 @@ public class ServiceState implements Parcelable { * Returns a copy of self with location-identifying information removed. * Always clears the NetworkRegistrationInfo's CellIdentity fields, but if removeCoarseLocation * is true, clears other info as well. + * + * @param removeCoarseLocation Whether to also remove coarse location information. + * if false, it only clears fine location information such as + * NetworkRegistrationInfo's CellIdentity fields; If true, it will + * also remove other location information such as operator's MCC + * and MNC. + * @return the copied ServiceState with location info sanitized. * @hide */ - public ServiceState sanitizeLocationInfo(boolean removeCoarseLocation) { + @SystemApi + @NonNull + public ServiceState createLocationInfoSanitizedCopy(boolean removeCoarseLocation) { ServiceState state = new ServiceState(this); synchronized (state.mNetworkRegistrationInfos) { List<NetworkRegistrationInfo> networkRegistrationInfos = @@ -1975,4 +2046,27 @@ public class ServiceState implements Parcelable { public boolean isIwlanPreferred() { return mIsIwlanPreferred; } + /** + * @return {@code true}Returns True whenever the modem is searching for service. + * To check both CS and PS domain + */ + + public boolean isSearching() { + NetworkRegistrationInfo psRegState = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + + if (psRegState != null && psRegState.getRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) { + return true; + } + + NetworkRegistrationInfo csRegState = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + + if (csRegState != null && csRegState.getRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) { + return true; + } + return false; + } } diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index 9aafc1be5831..483ccc437f89 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -17,12 +17,17 @@ package android.telephony; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import android.os.SystemClock; + +import com.android.telephony.Rlog; import java.util.ArrayList; import java.util.List; @@ -74,6 +79,9 @@ public class SignalStrength implements Parcelable { /* The type of signal measurement */ private static final String MEASUREMENT_TYPE_RSCP = "rscp"; + // timeStamp of signalStrength in nanoseconds since boot + private long mTimestamp = Long.MAX_VALUE; + CellSignalStrengthCdma mCdma; CellSignalStrengthGsm mGsm; CellSignalStrengthWcdma mWcdma; @@ -132,6 +140,7 @@ public class SignalStrength implements Parcelable { mTdscdma = tdscdma; mLte = lte; mNr = nr; + mTimestamp = SystemClock.elapsedRealtimeNanos(); } /** @@ -266,6 +275,7 @@ public class SignalStrength implements Parcelable { mTdscdma.updateLevel(cc, ss); mLte.updateLevel(cc, ss); mNr.updateLevel(cc, ss); + mTimestamp = SystemClock.elapsedRealtimeNanos(); } /** @@ -275,8 +285,8 @@ public class SignalStrength implements Parcelable { * * @hide */ - @UnsupportedAppUsage - public SignalStrength(SignalStrength s) { + @SystemApi + public SignalStrength(@NonNull SignalStrength s) { copyFrom(s); } @@ -291,6 +301,7 @@ public class SignalStrength implements Parcelable { mTdscdma = new CellSignalStrengthTdscdma(s.mTdscdma); mLte = new CellSignalStrengthLte(s.mLte); mNr = new CellSignalStrengthNr(s.mNr); + mTimestamp = s.getTimestampNanos(); } /** @@ -308,6 +319,7 @@ public class SignalStrength implements Parcelable { mTdscdma = in.readParcelable(CellSignalStrengthTdscdma.class.getClassLoader()); mLte = in.readParcelable(CellSignalStrengthLte.class.getClassLoader()); mNr = in.readParcelable(CellSignalStrengthLte.class.getClassLoader()); + mTimestamp = in.readLong(); } /** @@ -320,9 +332,18 @@ public class SignalStrength implements Parcelable { out.writeParcelable(mTdscdma, flags); out.writeParcelable(mLte, flags); out.writeParcelable(mNr, flags); + out.writeLong(mTimestamp); } /** + * @return mTimestamp in nanoseconds + */ + @SuppressLint("MethodNameUnits") + public long getTimestampNanos() { + return mTimestamp; + } + + /** * {@link Parcelable#describeContents} */ public int describeContents() { @@ -332,17 +353,16 @@ public class SignalStrength implements Parcelable { /** * {@link Parcelable.Creator} * - * @hide */ - @UnsupportedAppUsage - public static final @android.annotation.NonNull Parcelable.Creator<SignalStrength> CREATOR = new Parcelable.Creator() { - public SignalStrength createFromParcel(Parcel in) { - return new SignalStrength(in); - } + public static final @android.annotation.NonNull Parcelable.Creator<SignalStrength> CREATOR = + new Parcelable.Creator<SignalStrength>() { + public SignalStrength createFromParcel(Parcel in) { + return new SignalStrength(in); + } - public SignalStrength[] newArray(int size) { - return new SignalStrength[size]; - } + public SignalStrength[] newArray(int size) { + return new SignalStrength[size]; + } }; /** diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 6c2dd85076fc..0ba36b17f4ad 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -16,6 +16,7 @@ package android.telephony; +import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; @@ -24,15 +25,13 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.database.CursorWindow; import android.net.Uri; -import android.os.Binder; -import android.os.BaseBundle; import android.os.Build; import android.os.Bundle; import android.os.RemoteException; @@ -1578,7 +1577,7 @@ public final class SmsManager { } /** - * Copy a raw SMS PDU to the ICC. + * Copies a raw SMS PDU to the ICC. * ICC (Integrated Circuit Card) is the card of the device. * For example, this can be the SIM or USIM for GSM. * @@ -1592,21 +1591,26 @@ public final class SmsManager { * operation is performed on the correct subscription. * </p> * - * @param smsc the SMSC for this message, or NULL for the default SMSC - * @param pdu the raw PDU to store - * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, - * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) - * @return true for success + * @param smsc the SMSC for this messag or null for the default SMSC. + * @param pdu the raw PDU to store. + * @param status message status. One of these status: + * <code>STATUS_ON_ICC_READ</code> + * <code>STATUS_ON_ICC_UNREAD</code> + * <code>STATUS_ON_ICC_SENT</code> + * <code>STATUS_ON_ICC_UNSENT</code> + * @return true for success. Otherwise false. * - * @throws IllegalArgumentException if pdu is NULL - * {@hide} + * @throws IllegalArgumentException if pdu is null. + * @hide */ - @UnsupportedAppUsage - public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) { + @SystemApi + @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC) + public boolean copyMessageToIcc( + @Nullable byte[] smsc, @NonNull byte[] pdu, @StatusOnIcc int status) { boolean success = false; - if (null == pdu) { - throw new IllegalArgumentException("pdu is NULL"); + if (pdu == null) { + throw new IllegalArgumentException("pdu is null"); } try { ISms iSms = getISmsService(); @@ -1623,7 +1627,7 @@ public final class SmsManager { } /** - * Delete the specified message from the ICC. + * Deletes the specified message from the ICC. * ICC (Integrated Circuit Card) is the card of the device. * For example, this can be the SIM or USIM for GSM. * @@ -1637,14 +1641,16 @@ public final class SmsManager { * operation is performed on the correct subscription. * </p> * - * @param messageIndex is the record index of the message on ICC - * @return true for success + * @param messageIndex This is the same index used to access a message + * from {@link #getMessagesFromIcc()}. + * @return true for success, false if the operation fails. Failure can be due to IPC failure, + * RIL/modem error which results in SMS failed to be deleted on SIM * * {@hide} */ - @UnsupportedAppUsage - public boolean - deleteMessageFromIcc(int messageIndex) { + @SystemApi + @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC) + public boolean deleteMessageFromIcc(int messageIndex) { boolean success = false; try { @@ -1686,6 +1692,7 @@ public final class SmsManager { * {@hide} */ @UnsupportedAppUsage + @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC) public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { boolean success = false; @@ -1704,7 +1711,7 @@ public final class SmsManager { } /** - * Retrieves all messages currently stored on ICC. + * Retrieves all messages currently stored on the ICC. * ICC (Integrated Circuit Card) is the card of the device. * For example, this can be the SIM or USIM for GSM. * @@ -1718,8 +1725,22 @@ public final class SmsManager { * operation is performed on the correct subscription. * </p> * + * @return <code>List</code> of <code>SmsMessage</code> objects + * + * {@hide} + */ + @SystemApi + @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC) + public @NonNull List<SmsMessage> getMessagesFromIcc() { + return getAllMessagesFromIcc(); + } + + /** * @return <code>ArrayList</code> of <code>SmsMessage</code> objects * + * This is similar to {@link #getMessagesFromIcc} except that it will return ArrayList. + * Suggested to use {@link #getMessagesFromIcc} instead. + * * {@hide} */ @UnsupportedAppUsage @@ -1856,8 +1877,7 @@ public final class SmsManager { } /** - * Create a list of <code>SmsMessage</code>s from a list of RawSmsData - * records returned by <code>getAllMessagesFromIcc()</code> + * Creates a list of <code>SmsMessage</code>s from a list of SmsRawData records. * * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier * applications or the Telephony framework and will never trigger an SMS disambiguation @@ -1869,8 +1889,7 @@ public final class SmsManager { * operation is performed on the correct subscription. * </p> * - * @param records SMS EF records, returned by - * <code>getAllMessagesFromIcc</code> + * @param records SMS EF records. * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. */ private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { @@ -1881,7 +1900,7 @@ public final class SmsManager { SmsRawData data = records.get(i); // List contains all records, including "free" records (null) if (data != null) { - SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes(), + SmsMessage sms = SmsMessage.createFromEfRecord(i + 1, data.getBytes(), getSubscriptionId()); if (sms != null) { messages.add(sms); @@ -2021,6 +2040,17 @@ public final class SmsManager { return ret; } + /** @hide */ + @IntDef(prefix = { "STATUS_ON_ICC_" }, value = { + STATUS_ON_ICC_FREE, + STATUS_ON_ICC_READ, + STATUS_ON_ICC_UNREAD, + STATUS_ON_ICC_SENT, + STATUS_ON_ICC_UNSENT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface StatusOnIcc {} + // see SmsMessage.getStatusOnIcc /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ @@ -2409,33 +2439,32 @@ public final class SmsManager { /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */ public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS"; - /** Represents the received SMS message for importing {@hide} */ - public static final int SMS_TYPE_INCOMING = 0; - /** Represents the sent SMS message for importing {@hide} */ - public static final int SMS_TYPE_OUTGOING = 1; - - /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */ - public static final String MESSAGE_STATUS_SEEN = "seen"; - /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */ - public static final String MESSAGE_STATUS_READ = "read"; - /** - * Get carrier-dependent configuration values. + * Get carrier-dependent MMS configuration values. * * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier - * applications or the Telephony framework and will never trigger an SMS disambiguation - * dialog. If this method is called on a device that has multiple active subscriptions, this - * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined - * default subscription is defined, the subscription ID associated with this message will be - * INVALID, which will result in the operation being completed on the subscription associated - * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the - * operation is performed on the correct subscription. + * applications or the Telephony framework and will never trigger an SMS disambiguation dialog. + * If this method is called on a device that has multiple active subscriptions, this {@link + * SmsManager} instance has been created with {@link #getDefault()}, and no user-defined default + * subscription is defined, the subscription ID associated with this message will be INVALID, + * which will result in the operation being completed on the subscription associated with + * logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation is + * performed on the correct subscription. * </p> * - * @return bundle key/values pairs of configuration values + * @return the bundle key/values pairs that contains MMS configuration values */ + @Nullable public Bundle getCarrierConfigValues() { - return MmsManager.getInstance().getCarrierConfigValues(getSubscriptionId()); + try { + ISms iSms = getISmsService(); + if (iSms != null) { + return iSms.getCarrierConfigValuesForSubscriber(getSubscriptionId()); + } + } catch (RemoteException ex) { + // ignore it + } + return null; } /** @@ -2677,7 +2706,7 @@ public final class SmsManager { ISms iccISms = getISmsServiceOrThrow(); if (iccISms != null) { return iccISms.checkSmsShortCodeDestination(getSubscriptionId(), - ActivityThread.currentPackageName(), destAddress, countryIso); + ActivityThread.currentPackageName(), null, destAddress, countryIso); } } catch (RemoteException e) { Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e); diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index 392d3eb37686..8d9b1dd438ea 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -16,11 +16,18 @@ package android.telephony; +import com.android.telephony.Rlog; + import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; +import android.Manifest; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.StringDef; -import android.annotation.UnsupportedAppUsage; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.os.Binder; import android.text.TextUtils; @@ -29,8 +36,10 @@ import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.Sms7BitEncodingTranslator; import com.android.internal.telephony.SmsConstants; +import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; +import com.android.internal.telephony.cdma.sms.UserData; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -54,6 +63,16 @@ public class SmsMessage { UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; } + /** @hide */ + @IntDef(prefix = { "ENCODING_" }, value = { + ENCODING_UNKNOWN, + ENCODING_7BIT, + ENCODING_8BIT, + ENCODING_16BIT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EncodingSize {} + /** User data text encoding code unit size */ public static final int ENCODING_UNKNOWN = 0; public static final int ENCODING_7BIT = 1; @@ -259,19 +278,32 @@ public class SmsMessage { } /** - * Create an SmsMessage from an SMS EF record. + * Creates an SmsMessage from an SMS EF record. * - * @param index Index of SMS record. This should be index in ArrayList - * returned by SmsManager.getAllMessagesFromSim + 1. + * @param index Index of SMS EF record. * @param data Record data. * @return An SmsMessage representing the record. * * @hide */ public static SmsMessage createFromEfRecord(int index, byte[] data) { + return createFromEfRecord(index, data, SmsManager.getDefaultSmsSubscriptionId()); + } + + /** + * Creates an SmsMessage from an SMS EF record. + * + * @param index Index of SMS EF record. + * @param data Record data. + * @param subId Subscription Id associated with the record. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data, int subId) { SmsMessageBase wrappedMessage; - if (isCdmaVoice()) { + if (isCdmaVoice(subId)) { wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( index, data); } else { @@ -279,34 +311,32 @@ public class SmsMessage { index, data); } - if (wrappedMessage != null) { - return new SmsMessage(wrappedMessage); - } else { - Rlog.e(LOG_TAG, "createFromEfRecord(): wrappedMessage is null"); - return null; - } + return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null; } /** - * Create an SmsMessage from an SMS EF record. + * Create an SmsMessage from a native SMS-Submit PDU, specified by Bluetooth Message Access + * Profile Specification v1.4.2 5.8. + * This is used by Bluetooth MAP profile to decode message when sending non UTF-8 SMS messages. * - * @param index Index of SMS record. This should be index in ArrayList - * returned by SmsManager.getAllMessagesFromSim + 1. - * @param data Record data. - * @param subId Subscription Id of the SMS - * @return An SmsMessage representing the record. + * @param data Message data. + * @param isCdma Indicates weather the type of the SMS is CDMA. + * @return An SmsMessage representing the message. * * @hide */ - public static SmsMessage createFromEfRecord(int index, byte[] data, int subId) { + @SystemApi + @Nullable + public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) { SmsMessageBase wrappedMessage; - if (isCdmaVoice(subId)) { + if (isCdma) { wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( - index, data); + 0, data); } else { + // Bluetooth uses its own method to decode GSM PDU so this part is not called. wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( - index, data); + 0, data); } return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null; @@ -555,13 +585,15 @@ public class SmsMessage { */ /** - * Get an SMS-SUBMIT PDU for a destination address and a message. + * Gets an SMS-SUBMIT PDU for a destination address and a message. * This method will not attempt to use any GSM national language 7 bit encodings. * - * @param scAddress Service Centre address. Null means use default. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is requested for this message. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. */ public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested) { @@ -574,17 +606,16 @@ public class SmsMessage { } /** - * Get an SMS-SUBMIT PDU for a destination address and a message. + * Gets an SMS-SUBMIT PDU for a destination address and a message. * This method will not attempt to use any GSM national language 7 bit encodings. * - * @param scAddress Service Centre address. Null means use default. + * @param scAddress Service Centre address. Null means use default. * @param destinationAddress the address of the destination for the message. - * @param message String representation of the message payload. - * @param statusReportRequested Indicates whether a report is requested for this message. - * @param subId Subscription of the message - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is requested for this message. + * @param subId subscription of the message. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. * @hide */ public static SubmitPdu getSubmitPdu(String scAddress, @@ -602,17 +633,16 @@ public class SmsMessage { } /** - * Get an SMS-SUBMIT PDU for a data message to a destination address & port. + * Gets an SMS-SUBMIT PDU for a data message to a destination address & port. * This method will not attempt to use any GSM national language 7 bit encodings. * - * @param scAddress Service Centre address. null == use default - * @param destinationAddress the address of the destination for the message - * @param destinationPort the port to deliver the message to at the - * destination - * @param data the data for the message - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param destinationPort the port to deliver the message to at the destination. + * @param data the data for the message. + * @param statusReportRequested indicates whether a report is requested for this message. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. */ public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, short destinationPort, byte[] data, @@ -630,6 +660,132 @@ public class SmsMessage { return new SubmitPdu(spb); } + // TODO: SubmitPdu class is used for SMS-DELIVER also now. Refactor for SubmitPdu and new + // DeliverPdu accordingly. + + /** + * Gets an SMS PDU to store in the ICC. + * + * @param subId subscription of the message. + * @param status message status. One of these status: + * <code>SmsManager.STATUS_ON_ICC_READ</code> + * <code>SmsManager.STATUS_ON_ICC_UNREAD</code> + * <code>SmsManager.STATUS_ON_ICC_SENT</code> + * <code>SmsManager.STATUS_ON_ICC_UNSENT</code> + * @param scAddress Service Centre address. Null means use default. + * @param address destination or originating address. + * @param message string representation of the message payload. + * @param date the time stamp the message was received. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. + * @hide + */ + @SystemApi + @Nullable + public static SubmitPdu getSmsPdu(int subId, @SmsManager.StatusOnIcc int status, + @Nullable String scAddress, @NonNull String address, @NonNull String message, + long date) { + SubmitPduBase spb; + if (isCdmaVoice(subId)) { // 3GPP2 format + if (status == SmsManager.STATUS_ON_ICC_READ + || status == SmsManager.STATUS_ON_ICC_UNREAD) { // Deliver PDU + spb = com.android.internal.telephony.cdma.SmsMessage.getDeliverPdu(address, + message, date); + } else { // Submit PDU + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + address, message, false /* statusReportRequested */, null /* smsHeader */); + } + } else { // 3GPP format + if (status == SmsManager.STATUS_ON_ICC_READ + || status == SmsManager.STATUS_ON_ICC_UNREAD) { // Deliver PDU + spb = com.android.internal.telephony.gsm.SmsMessage.getDeliverPdu(scAddress, + address, message, date); + } else { // Submit PDU + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + address, message, false /* statusReportRequested */, null /* header */); + } + } + + return spb != null ? new SubmitPdu(spb) : null; + } + + /** + * Get an SMS-SUBMIT PDU's encoded message. + * This is used by Bluetooth MAP profile to handle long non UTF-8 SMS messages. + * + * @param isTypeGsm true when message's type is GSM, false when type is CDMA + * @param destinationAddress the address of the destination for the message + * @param message message content + * @param encoding User data text encoding code unit size + * @param languageTable GSM national language table to use, specified by 3GPP + * 23.040 9.2.3.24.16 + * @param languageShiftTable GSM national language shift table to use, specified by 3GPP + * 23.040 9.2.3.24.15 + * @param refNumber parameter to create SmsHeader + * @param seqNumber parameter to create SmsHeader + * @param msgCount parameter to create SmsHeader + * @return a byte[] containing the encoded message + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @SystemApi + @NonNull + public static byte[] getSubmitPduEncodedMessage(boolean isTypeGsm, + @NonNull String destinationAddress, + @NonNull String message, + @EncodingSize int encoding, int languageTable, + int languageShiftTable, int refNumber, + int seqNumber, int msgCount) { + byte[] data; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = refNumber; + concatRef.seqNumber = seqNumber; // 1-based sequence + concatRef.msgCount = msgCount; + // We currently set this to true since our messaging app will never + // send more than 255 parts (it converts the message to MMS well before that). + // However, we should support 3rd party messaging apps that might need 16-bit + // references + // Note: It's not sufficient to just flip this bit to true; it will have + // ripple effects (several calculations assume 8-bit ref). + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + + /* Depending on the type, call either GSM or CDMA getSubmitPdu(). The encoding + * will be determined(again) by getSubmitPdu(). + * All packets need to be encoded using the same encoding, as the bMessage + * only have one filed to describe the encoding for all messages in a concatenated + * SMS... */ + if (encoding == ENCODING_7BIT) { + smsHeader.languageTable = languageTable; + smsHeader.languageShiftTable = languageShiftTable; + } + + if (isTypeGsm) { + data = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(null, + destinationAddress, message, false, + SmsHeader.toByteArray(smsHeader), encoding, languageTable, + languageShiftTable).encodedMessage; + } else { // SMS_TYPE_CDMA + UserData uData = new UserData(); + uData.payloadStr = message; + uData.userDataHeader = smsHeader; + if (encoding == ENCODING_7BIT) { + uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + } else { // assume UTF-16 + uData.msgEncoding = UserData.ENCODING_UNICODE_16; + } + uData.msgEncodingSet = true; + data = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( + destinationAddress, uData, false).encodedMessage; + } + if (data == null) { + return new byte[0]; + } + return data; + } + /** * Returns the address of the SMS service center that relayed this message * or null if there is none. @@ -1038,10 +1194,10 @@ public class SmsMessage { } /** - * {@hide} * Returns the recipient address(receiver) of this SMS message in String form or null if * unavailable. */ + @Nullable public String getRecipientAddress() { return mWrappedSmsMessage.getRecipientAddress(); } diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index bbde1f48aed7..2d8e2376b9d8 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -16,9 +16,11 @@ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 376a5e00ae97..d4ab04cc2170 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED; @@ -32,9 +34,9 @@ import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.BroadcastOptions; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; @@ -48,7 +50,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.os.ParcelUuid; import android.os.Process; @@ -64,6 +65,7 @@ import android.util.Pair; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.util.HandlerExecutor; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -1040,6 +1042,23 @@ public class SubscriptionManager { */ public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { if (listener == null) return; + addOnSubscriptionsChangedListener(listener.mExecutor, listener); + } + + /** + * Register for changes to the list of active {@link SubscriptionInfo} records or to the + * individual records themselves. When a change occurs the onSubscriptionsChanged method of + * the listener will be invoked immediately if there has been a notification. The + * onSubscriptionChanged method will also be triggered once initially when calling this + * function. + * + * @param listener an instance of {@link OnSubscriptionsChangedListener} with + * onSubscriptionsChanged overridden. + * @param executor the executor that will execute callbacks. + */ + public void addOnSubscriptionsChangedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull OnSubscriptionsChangedListener listener) { String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>"; if (DBG) { logd("register OnSubscriptionsChangedListener pkgName=" + pkgName @@ -1051,7 +1070,7 @@ public class SubscriptionManager { mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); if (telephonyRegistryManager != null) { telephonyRegistryManager.addOnSubscriptionsChangedListener(listener, - listener.mExecutor); + executor); } } @@ -1186,7 +1205,8 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName()); + subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { // ignore it @@ -1197,12 +1217,17 @@ public class SubscriptionManager { } /** - * Get the active SubscriptionInfo associated with the iccId + * Gets an active SubscriptionInfo {@link SubscriptionInfo} associated with the Sim IccId. + * * @param iccId the IccId of SIM card * @return SubscriptionInfo, maybe null if its not active + * * @hide */ - public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) { + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @Nullable + @SystemApi + public SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String iccId) { if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId); if (iccId == null) { logd("[getActiveSubscriptionInfoForIccIndex]- null iccid"); @@ -1214,7 +1239,8 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName()); + result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { // ignore it @@ -1248,7 +1274,7 @@ public class SubscriptionManager { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex, - mContext.getOpPackageName()); + mContext.getOpPackageName(), null); } } catch (RemoteException ex) { // ignore it @@ -1271,7 +1297,8 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - result = iSub.getAllSubInfoList(mContext.getOpPackageName()); + result = iSub.getAllSubInfoList(mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { // ignore it @@ -1346,7 +1373,8 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName()); + activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { // ignore it @@ -1396,7 +1424,8 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName()); + result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { // ignore it @@ -1513,7 +1542,8 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - result = iSub.getAllSubInfoCount(mContext.getOpPackageName()); + result = iSub.getAllSubInfoCount(mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { // ignore it @@ -1541,7 +1571,8 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - result = iSub.getActiveSubInfoCount(mContext.getOpPackageName()); + result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { // ignore it @@ -2278,7 +2309,7 @@ public class SubscriptionManager { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { resultValue = iSub.getSubscriptionProperty(subId, propKey, - context.getOpPackageName()); + context.getOpPackageName(), null); } } catch (RemoteException ex) { // ignore it @@ -2419,7 +2450,8 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - return iSub.isActiveSubId(subId, mContext.getOpPackageName()); + return iSub.isActiveSubId(subId, mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { } @@ -2472,6 +2504,8 @@ public class SubscriptionManager { * may not be displayed or used by decision making logic. * @throws SecurityException if the caller doesn't meet the requirements * outlined above. + * @throws IllegalArgumentException if plans don't meet the requirements + * defined in {@link SubscriptionPlan}. */ public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) { try { @@ -2645,8 +2679,7 @@ public class SubscriptionManager { /** * Checks whether the app with the given context is authorized to manage the given subscription - * according to its metadata. Only supported for embedded subscriptions (if - * {@code SubscriptionInfo#isEmbedded} returns true). + * according to its metadata. * * @param info The subscription to check. * @return whether the app is authorized to manage this subscription per its metadata. @@ -2659,16 +2692,16 @@ public class SubscriptionManager { * Checks whether the given app is authorized to manage the given subscription. An app can only * be authorized if it is included in the {@link android.telephony.UiccAccessRule} of the * {@link android.telephony.SubscriptionInfo} with the access status. - * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} - * returns true). * * @param info The subscription to check. * @param packageName Package name of the app to check. * @return whether the app is authorized to manage this subscription per its access rules. * @hide */ - public boolean canManageSubscription(SubscriptionInfo info, String packageName) { - if (info == null || info.getAllAccessRules() == null) { + @SystemApi + public boolean canManageSubscription(@Nullable SubscriptionInfo info, + @Nullable String packageName) { + if (info == null || info.getAllAccessRules() == null || packageName == null) { return false; } PackageManager packageManager = mContext.getPackageManager(); @@ -2787,13 +2820,14 @@ public class SubscriptionManager { @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public @NonNull List<SubscriptionInfo> getOpportunisticSubscriptions() { - String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + String contextPkg = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + String contextFeature = null; List<SubscriptionInfo> subInfoList = null; try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - subInfoList = iSub.getOpportunisticSubscriptions(pkgForDebug); + subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature); } } catch (RemoteException ex) { // ignore it @@ -3031,7 +3065,8 @@ public class SubscriptionManager { @RequiresPermission(Manifest.permission.READ_PHONE_STATE) public @NonNull List<SubscriptionInfo> getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid) { Preconditions.checkNotNull(groupUuid, "groupUuid can't be null"); - String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + String contextPkg = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + String contextFeature = null; if (VDBG) { logd("[getSubscriptionsInGroup]+ groupUuid:" + groupUuid); } @@ -3040,7 +3075,7 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - result = iSub.getSubscriptionsInGroup(groupUuid, pkgForDebug); + result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature); } else { if (!isSystemProcess()) { throw new IllegalStateException("telephony service is null."); @@ -3163,6 +3198,34 @@ public class SubscriptionManager { } /** + * Set uicc applications being enabled or disabled. + * The value will be remembered on the subscription and will be applied whenever it's present. + * If the subscription in currently present, it will also apply the setting to modem + * immediately. + * + * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required + * + * @param enabled whether uicc applications are enabled or disabled. + * @param subscriptionId which subscription to operate on. + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setUiccApplicationsEnabled(boolean enabled, int subscriptionId) { + if (VDBG) { + logd("setUiccApplicationsEnabled subId= " + subscriptionId + " enable " + enabled); + } + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + iSub.setUiccApplicationsEnabled(enabled, subscriptionId); + } + } catch (RemoteException ex) { + // ignore it + } + } + + /** * Whether it's supported to disable / re-enable a subscription on a physical (non-euicc) SIM. * * Physical SIM refers non-euicc, or aka non-programmable SIM. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 85f25811b959..ef631b8a05dc 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -17,6 +17,8 @@ package android.telephony; import static android.content.Context.TELECOM_SERVICE; +import static android.provider.Telephony.Carriers.DPC_URI; +import static android.provider.Telephony.Carriers.INVALID_APN_ID; import static com.android.internal.util.Preconditions.checkNotNull; @@ -34,16 +36,17 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; import android.app.ActivityThread; import android.app.PendingIntent; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkStats; import android.net.Uri; @@ -70,11 +73,13 @@ import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.Annotation.ApnType; import android.telephony.Annotation.CallState; -import android.telephony.Annotation.DataState; import android.telephony.Annotation.NetworkType; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; +import android.telephony.Annotation.UiccAppType; import android.telephony.VisualVoicemailService.VisualVoicemailTask; +import android.telephony.data.ApnSetting; +import android.telephony.data.ApnSetting.MvnoType; import android.telephony.emergency.EmergencyNumber; import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories; import android.telephony.ims.ImsMmTelManager; @@ -102,6 +107,7 @@ import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.SmsApplication; +import com.android.telephony.Rlog; import dalvik.system.VMRuntime; @@ -190,11 +196,8 @@ public class TelephonyManager { NETWORK_SELECTION_MODE_MANUAL}) public @interface NetworkSelectionMode {} - /** @hide */ public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; - /** @hide */ public static final int NETWORK_SELECTION_MODE_AUTO = 1; - /** @hide */ public static final int NETWORK_SELECTION_MODE_MANUAL = 2; /** The otaspMode passed to PhoneStateListener#onOtaspChanged */ @@ -375,6 +378,10 @@ public class TelephonyManager { return ActivityThread.currentOpPackageName(); } + private String getFeatureId() { + return null; + } + private boolean isSystemProcess() { return Process.myUid() == Process.SYSTEM_UID; } @@ -765,30 +772,6 @@ public class TelephonyManager { public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause"; /** - * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast - * for an String containing the data APN type. - * - * <p class="note"> - * Retrieve with - * {@link android.content.Intent#getStringExtra(String name)}. - * - * @hide - */ - public static final String EXTRA_DATA_APN_TYPE = PhoneConstants.DATA_APN_TYPE_KEY; - - /** - * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast - * for an String containing the data APN. - * - * <p class="note"> - * Retrieve with - * {@link android.content.Intent#getStringExtra(String name)}. - * - * @hide - */ - public static final String EXTRA_DATA_APN = PhoneConstants.DATA_APN_KEY; - - /** * Broadcast intent action for letting the default dialer to know to show voicemail * notification. * @@ -1450,25 +1433,6 @@ public class TelephonyManager { public static final String EXTRA_SIM_COMBINATION_NAMES = "android.telephony.extra.SIM_COMBINATION_NAMES"; - /** - * Broadcast Action: The time was set by the carrier (typically by the NITZ string). - * This is a sticky broadcast. - * The intent will have the following extra values:</p> - * <ul> - * <li><em>time</em> - The time as a long in UTC milliseconds.</li> - * </ul> - * - * <p class="note"> - * Requires the READ_PHONE_STATE permission. - * - * <p class="note">This is a protected intent that can only be sent - * by the system. - * - * @hide - */ - @SystemApi - public static final String ACTION_NETWORK_SET_TIME = "android.telephony.action.NETWORK_SET_TIME"; - // // // Device Info @@ -1507,7 +1471,8 @@ public class TelephonyManager { if (telephony == null) return null; try { - return telephony.getDeviceSoftwareVersionForSlot(slotIndex, getOpPackageName()); + return telephony.getDeviceSoftwareVersionForSlot(slotIndex, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1548,7 +1513,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return null; - return telephony.getDeviceId(mContext.getOpPackageName()); + return telephony.getDeviceIdWithFeature(mContext.getOpPackageName(), + null); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1592,7 +1558,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName()); + return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName(), + null); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1650,7 +1617,7 @@ public class TelephonyManager { if (telephony == null) return null; try { - return telephony.getImeiForSlot(slotIndex, getOpPackageName()); + return telephony.getImeiForSlot(slotIndex, getOpPackageName(), getFeatureId()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1744,7 +1711,7 @@ public class TelephonyManager { if (telephony == null) return null; try { - String meid = telephony.getMeidForSlot(slotIndex, getOpPackageName()); + String meid = telephony.getMeidForSlot(slotIndex, getOpPackageName(), getFeatureId()); if (TextUtils.isEmpty(meid)) { Log.d(TAG, "getMeid: return null because MEID is not available"); return null; @@ -1845,7 +1812,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - String nai = info.getNaiForSubscriber(subId, mContext.getOpPackageName()); + String nai = info.getNaiForSubscriber(subId, mContext.getOpPackageName(), + null); if (Log.isLoggable(TAG, Log.VERBOSE)) { Rlog.v(TAG, "Nai = " + nai); } @@ -1878,13 +1846,9 @@ public class TelephonyManager { return null; } - Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName()); - if (bundle == null || bundle.isEmpty()) { - Rlog.d(TAG, "getCellLocation returning null because CellLocation is unavailable"); - return null; - } - - CellLocation cl = CellLocation.newFromBundle(bundle); + CellIdentity cellIdentity = telephony.getCellLocation(mContext.getOpPackageName(), + null); + CellLocation cl = cellIdentity.asCellLocation(); if (cl == null || cl.isEmpty()) { Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or" + " phone type doesn't match CellLocation type"); @@ -1966,7 +1930,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return null; - return telephony.getNeighboringCellInfo(mContext.getOpPackageName()); + return telephony.getNeighboringCellInfo(mContext.getOpPackageName(), + null); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1982,6 +1947,16 @@ public class TelephonyManager { public static final int PHONE_TYPE_CDMA = PhoneConstants.PHONE_TYPE_CDMA; /** Phone is via SIP. */ public static final int PHONE_TYPE_SIP = PhoneConstants.PHONE_TYPE_SIP; + /** Phone is via IMS. */ + public static final int PHONE_TYPE_IMS = PhoneConstants.PHONE_TYPE_IMS; + + /** + * Phone is via Third Party. + * + * @hide + */ + @SystemApi + public static final int PHONE_TYPE_THIRD_PARTY = PhoneConstants.PHONE_TYPE_THIRD_PARTY; /** * Returns the current phone type. @@ -2394,7 +2369,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return ""; return telephony.getNetworkCountryIsoForPhone(getPhoneId(), - null /* no permission check */); + null /* no permission check */, null); } catch (RemoteException ex) { return ""; } @@ -2434,7 +2409,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return ""; - return telephony.getNetworkCountryIsoForPhone(slotIndex, getOpPackageName()); + return telephony.getNetworkCountryIsoForPhone(slotIndex, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { return ""; } @@ -2566,7 +2542,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName()); + return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName(), + getFeatureId()); } else { // This can happen when the ITelephony interface is not up yet. return NETWORK_TYPE_UNKNOWN; @@ -2630,7 +2607,8 @@ public class TelephonyManager { try{ ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getDataNetworkTypeForSubscriber(subId, getOpPackageName()); + return telephony.getDataNetworkTypeForSubscriber(subId, getOpPackageName(), + getFeatureId()); } else { // This can happen when the ITelephony interface is not up yet. return NETWORK_TYPE_UNKNOWN; @@ -2666,7 +2644,8 @@ public class TelephonyManager { try{ ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getVoiceNetworkTypeForSubscriber(subId, getOpPackageName()); + return telephony.getVoiceNetworkTypeForSubscriber(subId, getOpPackageName(), + getFeatureId()); } else { // This can happen when the ITelephony interface is not up yet. return NETWORK_TYPE_UNKNOWN; @@ -2806,6 +2785,55 @@ public class TelephonyManager { } } + /** + * Returns the bitmask for a given technology (network type) + * @param networkType for which bitmask is returned + * @return the network type bitmask + * {@hide} + */ + public static @NetworkTypeBitMask long getBitMaskForNetworkType(@NetworkType int networkType) { + switch(networkType) { + case NETWORK_TYPE_GSM: + return NETWORK_TYPE_BITMASK_GSM; + case NETWORK_TYPE_GPRS: + return NETWORK_TYPE_BITMASK_GPRS; + case NETWORK_TYPE_EDGE: + return NETWORK_TYPE_BITMASK_EDGE; + case NETWORK_TYPE_CDMA: + return NETWORK_TYPE_BITMASK_CDMA; + case NETWORK_TYPE_1xRTT: + return NETWORK_TYPE_BITMASK_1xRTT; + case NETWORK_TYPE_EVDO_0: + return NETWORK_TYPE_BITMASK_EVDO_0; + case NETWORK_TYPE_EVDO_A: + return NETWORK_TYPE_BITMASK_EVDO_A; + case NETWORK_TYPE_EVDO_B: + return NETWORK_TYPE_BITMASK_EVDO_B; + case NETWORK_TYPE_EHRPD: + return NETWORK_TYPE_BITMASK_EHRPD; + case NETWORK_TYPE_HSUPA: + return NETWORK_TYPE_BITMASK_HSUPA; + case NETWORK_TYPE_HSDPA: + return NETWORK_TYPE_BITMASK_HSDPA; + case NETWORK_TYPE_HSPA: + return NETWORK_TYPE_BITMASK_HSPA; + case NETWORK_TYPE_HSPAP: + return NETWORK_TYPE_BITMASK_HSPAP; + case NETWORK_TYPE_UMTS: + return NETWORK_TYPE_BITMASK_UMTS; + case NETWORK_TYPE_TD_SCDMA: + return NETWORK_TYPE_BITMASK_TD_SCDMA; + case NETWORK_TYPE_LTE: + return NETWORK_TYPE_BITMASK_LTE; + case NETWORK_TYPE_LTE_CA: + return NETWORK_TYPE_BITMASK_LTE_CA; + case NETWORK_TYPE_NR: + return NETWORK_TYPE_BITMASK_NR; + default: + return NETWORK_TYPE_BITMASK_UNKNOWN; + } + } + // // // SIM Card @@ -3460,7 +3488,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName()); + return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName(), + null); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -3504,7 +3533,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return PhoneConstants.LTE_ON_CDMA_UNKNOWN; - return telephony.getLteOnCdmaModeForSubscriber(subId, getOpPackageName()); + return telephony.getLteOnCdmaModeForSubscriber(subId, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { // Assume no ICC card if remote exception which shouldn't happen return PhoneConstants.LTE_ON_CDMA_UNKNOWN; @@ -3732,7 +3762,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName()); + return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName(), + null); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -3899,7 +3930,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getGroupIdLevel1ForSubscriber(getSubId(), mContext.getOpPackageName()); + return info.getGroupIdLevel1ForSubscriber(getSubId(), mContext.getOpPackageName(), + null); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -3922,7 +3954,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName()); + return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName(), + null); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -3972,7 +4005,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - number = telephony.getLine1NumberForDisplay(subId, mContext.getOpPackageName()); + number = telephony.getLine1NumberForDisplay(subId, mContext.getOpPackageName(), + null); } catch (RemoteException ex) { } catch (NullPointerException ex) { } @@ -3983,7 +4017,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName()); + return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName(), + null); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -4062,7 +4097,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony != null) alphaTag = telephony.getLine1AlphaTagForDisplay(subId, - getOpPackageName()); + getOpPackageName(), getFeatureId()); } catch (RemoteException ex) { } catch (NullPointerException ex) { } @@ -4073,7 +4108,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getLine1AlphaTagForSubscriber(subId, getOpPackageName()); + return info.getLine1AlphaTagForSubscriber(subId, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -4102,7 +4138,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.getMergedSubscriberIds(getSubId(), getOpPackageName()); + return telephony.getMergedSubscriberIds(getSubId(), getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { } catch (NullPointerException ex) { } @@ -4157,7 +4194,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getMsisdnForSubscriber(subId, getOpPackageName()); + return info.getMsisdnForSubscriber(subId, getOpPackageName(), getFeatureId()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -4191,7 +4228,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getVoiceMailNumberForSubscriber(subId, getOpPackageName()); + return info.getVoiceMailNumberForSubscriber(subId, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -4315,8 +4353,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony - .getVisualVoicemailPackageName(mContext.getOpPackageName(), getSubId()); + return telephony.getVisualVoicemailPackageName(mContext.getOpPackageName(), + getFeatureId(), getSubId()); } } catch (RemoteException ex) { } catch (NullPointerException ex) { @@ -4752,7 +4790,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return 0; - return telephony.getVoiceMessageCountForSubscriber(subId, getOpPackageName()); + return telephony.getVoiceMessageCountForSubscriber(subId, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { return 0; } catch (NullPointerException ex) { @@ -4788,7 +4827,8 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getVoiceMailAlphaTagForSubscriber(subId, getOpPackageName()); + return info.getVoiceMailAlphaTagForSubscriber(subId, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -4878,7 +4918,9 @@ public class TelephonyManager { * not present or not loaded * @hide */ - @UnsupportedAppUsage + @Nullable + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getIsimImpu() { try { IPhoneSubInfo info = getSubscriberInfo(); @@ -5184,7 +5226,7 @@ public class TelephonyManager { } else if (listener.mSubId != null) { subId = listener.mSubId; } - registry.listenForSubscriber(subId, getOpPackageName(), + registry.listenForSubscriber(subId, getOpPackageName(), getFeatureId(), listener.callback, events, notifyNow); } else { Rlog.w(TAG, "telephony registry not ready."); @@ -5214,7 +5256,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return -1; - return telephony.getCdmaEriIconIndexForSubscriber(subId, getOpPackageName()); + return telephony.getCdmaEriIconIndexForSubscriber(subId, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { // the phone process is restarting. return -1; @@ -5249,7 +5292,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return -1; - return telephony.getCdmaEriIconModeForSubscriber(subId, getOpPackageName()); + return telephony.getCdmaEriIconModeForSubscriber(subId, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { // the phone process is restarting. return -1; @@ -5280,7 +5324,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return null; - return telephony.getCdmaEriTextForSubscriber(subId, getOpPackageName()); + return telephony.getCdmaEriTextForSubscriber(subId, getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { // the phone process is restarting. return null; @@ -5372,8 +5417,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return null; - return telephony.getAllCellInfo( - getOpPackageName()); + return telephony.getAllCellInfo(getOpPackageName(), getFeatureId()); } catch (RemoteException ex) { } catch (NullPointerException ex) { } @@ -5473,7 +5517,7 @@ public class TelephonyManager { Binder.restoreCallingIdentity(identity); } } - }, getOpPackageName()); + }, getOpPackageName(), getFeatureId()); } catch (RemoteException ex) { } } @@ -5524,7 +5568,7 @@ public class TelephonyManager { Binder.restoreCallingIdentity(identity); } } - }, getOpPackageName(), workSource); + }, getOpPackageName(), getFeatureId(), workSource); } catch (RemoteException ex) { } } @@ -5681,7 +5725,10 @@ public class TelephonyManager { * @param AID Application id. See ETSI 102.221 and 101.220. * @param p2 P2 parameter (described in ISO 7816-4). * @return an IccOpenLogicalChannelResponse object. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) { return iccOpenLogicalChannel(getSubId(), AID, p2); } @@ -5712,7 +5759,10 @@ public class TelephonyManager { * @param p2 P2 parameter (described in ISO 7816-4). * @return an IccOpenLogicalChannelResponse object. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID, int p2) { try { ITelephony telephony = getITelephony(); @@ -5740,7 +5790,10 @@ public class TelephonyManager { * iccOpenLogicalChannel. * @return true if the channel was closed successfully. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) { @@ -5767,7 +5820,10 @@ public class TelephonyManager { * @param channel is the channel id to be closed as returned by a successful * iccOpenLogicalChannel. * @return true if the channel was closed successfully. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public boolean iccCloseLogicalChannel(int channel) { return iccCloseLogicalChannel(getSubId(), channel); } @@ -5786,7 +5842,10 @@ public class TelephonyManager { * iccOpenLogicalChannel. * @return true if the channel was closed successfully. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public boolean iccCloseLogicalChannel(int subId, int channel) { try { ITelephony telephony = getITelephony(); @@ -5822,7 +5881,10 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at the end, or null if * there is an issue connecting to the Telephony service. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @Nullable @@ -5860,7 +5922,10 @@ public class TelephonyManager { * @param data Data to be sent with the APDU. * @return The APDU response from the ICC card with the status appended at * the end. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public String iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data) { return iccTransmitApduLogicalChannel(getSubId(), channel, cla, @@ -5889,7 +5954,10 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public String iccTransmitApduLogicalChannel(int subId, int channel, int cla, int instruction, int p1, int p2, int p3, String data) { try { @@ -5925,7 +5993,10 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @NonNull @@ -5961,7 +6032,10 @@ public class TelephonyManager { * @param data Data to be sent with the APDU. * @return The APDU response from the ICC card with the status appended at * the end. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public String iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, int p3, String data) { return iccTransmitApduBasicChannel(getSubId(), cla, @@ -5988,7 +6062,10 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public String iccTransmitApduBasicChannel(int subId, int cla, int instruction, int p1, int p2, int p3, String data) { try { @@ -6016,7 +6093,10 @@ public class TelephonyManager { * @param p3 P3 value of the APDU command. * @param filePath * @return The APDU response. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, String filePath) { return iccExchangeSimIO(getSubId(), fileID, command, p1, p2, p3, filePath); @@ -6038,7 +6118,10 @@ public class TelephonyManager { * @param filePath * @return The APDU response. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2, int p3, String filePath) { try { @@ -6064,7 +6147,10 @@ public class TelephonyManager { * @return The APDU response from the ICC card in hexadecimal format * with the last 4 bytes being the status word. If the command fails, * returns an empty string. + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public String sendEnvelopeWithStatus(String content) { return sendEnvelopeWithStatus(getSubId(), content); } @@ -6084,7 +6170,10 @@ public class TelephonyManager { * with the last 4 bytes being the status word. If the command fails, * returns an empty string. * @hide + * @deprecated Use {@link android.se.omapi.SEService} APIs instead. */ + // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated. + @Deprecated public String sendEnvelopeWithStatus(int subId, String content) { try { ITelephony telephony = getITelephony(); @@ -6617,19 +6706,6 @@ public class TelephonyManager { } } - /** - * UICC SIM Application Types - * @hide - */ - @IntDef(prefix = { "APPTYPE_" }, value = { - APPTYPE_SIM, - APPTYPE_USIM, - APPTYPE_RUIM, - APPTYPE_CSIM, - APPTYPE_ISIM - }) - @Retention(RetentionPolicy.SOURCE) - public @interface UiccAppType{} /** UICC application type is SIM */ public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM; /** UICC application type is USIM */ @@ -6740,7 +6816,8 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return null; - return telephony.getForbiddenPlmns(subId, appType, mContext.getOpPackageName()); + return telephony.getForbiddenPlmns(subId, appType, mContext.getOpPackageName(), + getFeatureId()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -6774,7 +6851,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return -1; return telephony.setForbiddenPlmns( - getSubId(), APPTYPE_USIM, fplmns, getOpPackageName()); + getSubId(), APPTYPE_USIM, fplmns, getOpPackageName(), getFeatureId()); } catch (RemoteException ex) { Rlog.e(TAG, "setForbiddenPlmns RemoteException: " + ex.getMessage()); } catch (NullPointerException ex) { @@ -6795,7 +6872,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return new String[0]; - return telephony.getPcscfAddress(apnType, getOpPackageName()); + return telephony.getPcscfAddress(apnType, getOpPackageName(), getFeatureId()); } catch (RemoteException e) { return new String[0]; } @@ -7306,7 +7383,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getCellNetworkScanResults(getSubId(), getOpPackageName()); + return telephony.getCellNetworkScanResults(getSubId(), getOpPackageName(), + getFeatureId()); } } catch (RemoteException ex) { Rlog.e(TAG, "getAvailableNetworks RemoteException", ex); @@ -7361,7 +7439,7 @@ public class TelephonyManager { } } return mTelephonyScanManager.requestNetworkScan(getSubId(), request, executor, callback, - getOpPackageName()); + getOpPackageName(), getFeatureId()); } /** @@ -7443,14 +7521,18 @@ public class TelephonyManager { * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} - - * @return the network selection mode. + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * - * @hide + * @return the network selection mode. */ - @NetworkSelectionMode - @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) - public int getNetworkSelectionMode() { + @SuppressAutoDoc // No support for carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE + }) + public @NetworkSelectionMode int getNetworkSelectionMode() { int mode = NETWORK_SELECTION_MODE_UNKNOWN; try { ITelephony telephony = getITelephony(); @@ -7573,12 +7655,12 @@ public class TelephonyManager { /** * Check whether DUN APN is required for tethering. * <p> - * Requires Permission: READ_PRIVILEGED_PHONE_STATE. + * Requires Permission: MODIFY_PHONE_STATE. * * @return {@code true} if DUN APN is required for tethering. * @hide */ - @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @SystemApi public boolean isTetheringApnRequired() { return isTetheringApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId())); @@ -8033,7 +8115,7 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.isRadioOn(getOpPackageName()); + return telephony.isRadioOnWithFeature(getOpPackageName(), getFeatureId()); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#isRadioOn", e); } @@ -8047,9 +8129,9 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.supplyPin(pin); + return telephony.supplyPinForSubscriber(getSubId(), pin); } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#supplyPin", e); + Log.e(TAG, "Error calling ITelephony#supplyPinForSubscriber", e); } return false; } @@ -8061,9 +8143,9 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.supplyPuk(puk, pin); + return telephony.supplyPukForSubscriber(getSubId(), puk, pin); } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#supplyPuk", e); + Log.e(TAG, "Error calling ITelephony#supplyPukForSubscriber", e); } return false; } @@ -8075,9 +8157,9 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.supplyPinReportResult(pin); + return telephony.supplyPinReportResultForSubscriber(getSubId(), pin); } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#supplyPinReportResult", e); + Log.e(TAG, "Error calling ITelephony#supplyPinReportResultForSubscriber", e); } return new int[0]; } @@ -8089,7 +8171,7 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.supplyPukReportResult(puk, pin); + return telephony.supplyPukReportResultForSubscriber(getSubId(), puk, pin); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#]", e); } @@ -8346,7 +8428,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getRadioPowerState(getSlotIndex(), mContext.getOpPackageName()); + return telephony.getRadioPowerState(getSlotIndex(), mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { // This could happen if binder process crashes. @@ -8704,7 +8787,7 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.isVideoCallingEnabled(getOpPackageName()); + return telephony.isVideoCallingEnabled(getOpPackageName(), getFeatureId()); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#isVideoCallingEnabled", e); } @@ -8720,7 +8803,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.canChangeDtmfToneLength(mSubId, getOpPackageName()); + return telephony.canChangeDtmfToneLength(mSubId, getOpPackageName(), + getFeatureId()); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e); @@ -8739,7 +8823,7 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.isWorldPhone(mSubId, getOpPackageName()); + return telephony.isWorldPhone(mSubId, getOpPackageName(), getFeatureId()); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#isWorldPhone", e); @@ -9020,15 +9104,20 @@ public class TelephonyManager { } /** - * Requested state of SIM - * - * CARD_POWER_DOWN * Powers down the SIM. SIM must be up prior. - * - * CARD_POWER_UP + * @hide + */ + @SystemApi + public static final int CARD_POWER_DOWN = 0; + + /** * Powers up the SIM normally. SIM must be down prior. - * - * CARD_POWER_UP_PASS_THROUGH + * @hide + */ + @SystemApi + public static final int CARD_POWER_UP = 1; + + /** * Powers up the SIM in PASS_THROUGH mode. SIM must be down prior. * When SIM is powered up in PASS_THOUGH mode, the modem does not send * any command to it (for example SELECT of MF, or TERMINAL CAPABILITY), @@ -9041,12 +9130,9 @@ public class TelephonyManager { * is activated, and normal behavior occurs at the next SIM initialization, * unless PASS_THROUGH mode is requested again. Hence, the last power-up mode * is NOT persistent across boots. On reboot, SIM will power up normally. + * @hide */ - /** @hide */ - public static final int CARD_POWER_DOWN = 0; - /** @hide */ - public static final int CARD_POWER_UP = 1; - /** @hide */ + @SystemApi public static final int CARD_POWER_UP_PASS_THROUGH = 2; /** @@ -9465,7 +9551,7 @@ public class TelephonyManager { ITelephony service = getITelephony(); if (service != null) { retval = service.getSubIdForPhoneAccountHandle( - phoneAccountHandle, mContext.getOpPackageName()); + phoneAccountHandle, mContext.getOpPackageName(), null); } } catch (RemoteException ex) { Log.e(TAG, "getSubscriptionId RemoteException", ex); @@ -9603,7 +9689,8 @@ public class TelephonyManager { try { ITelephony service = getITelephony(); if (service != null) { - return service.getServiceStateForSubscriber(subId, getOpPackageName()); + return service.getServiceStateForSubscriber(subId, getOpPackageName(), + getFeatureId()); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#getServiceStateForSubscriber", e); @@ -10198,6 +10285,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param enabled control enable or disable carrier data. + * @see #resetAllCarrierActions() * @hide */ @SystemApi @@ -10224,6 +10312,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param enabled control enable or disable radio. + * @see #resetAllCarrierActions() * @hide */ @SystemApi @@ -10250,6 +10339,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param report control start/stop reporting network status. + * @see #resetAllCarrierActions() * @hide */ @SystemApi @@ -10343,7 +10433,7 @@ public class TelephonyManager { try { ITelephony service = getITelephony(); if (service != null) { - return service.getClientRequestStats(getOpPackageName(), subId); + return service.getClientRequestStats(getOpPackageName(), getFeatureId(), subId); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#getClientRequestStats", e); @@ -10396,7 +10486,8 @@ public class TelephonyManager { * * @hide */ - @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isManualNetworkSelectionAllowed() { try { ITelephony telephony = getITelephony(); @@ -10631,7 +10722,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony != null) { return telephony.getNumberOfModemsWithSimultaneousDataConnections( - getSubId(), getOpPackageName()); + getSubId(), getOpPackageName(), getFeatureId()); } } catch (RemoteException ex) { // This could happen if binder process crashes. @@ -10987,7 +11078,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getEmergencyNumberList(mContext.getOpPackageName()); + return telephony.getEmergencyNumberList(mContext.getOpPackageName(), + null); } else { throw new IllegalStateException("telephony service is null."); } @@ -11042,7 +11134,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony != null) { emergencyNumberList = telephony.getEmergencyNumberList( - mContext.getOpPackageName()); + mContext.getOpPackageName(), null); if (emergencyNumberList != null) { for (Integer subscriptionId : emergencyNumberList.keySet()) { List<EmergencyNumber> numberList = emergencyNumberList.get(subscriptionId); @@ -11348,12 +11440,14 @@ public class TelephonyManager { android.Manifest.permission.READ_PHONE_STATE }) public int getPreferredOpportunisticDataSubscription() { - String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + String packageName = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + String featureId = null; int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; try { IOns iOpportunisticNetworkService = getIOns(); if (iOpportunisticNetworkService != null) { - subId = iOpportunisticNetworkService.getPreferredDataSubscriptionId(pkgForDebug); + subId = iOpportunisticNetworkService.getPreferredDataSubscriptionId( + packageName, featureId); } } catch (RemoteException ex) { Rlog.e(TAG, "getPreferredDataSubscriptionId RemoteException", ex); @@ -11480,7 +11574,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.isModemEnabledForSlot(slotIndex, mContext.getOpPackageName()); + return telephony.isModemEnabledForSlot(slotIndex, mContext.getOpPackageName(), + null); } } catch (RemoteException ex) { Log.e(TAG, "enableModem RemoteException", ex); @@ -11585,7 +11680,7 @@ public class TelephonyManager { try { ITelephony service = getITelephony(); if (service != null) { - return service.isMultiSimSupported(getOpPackageName()); + return service.isMultiSimSupported(getOpPackageName(), getFeatureId()); } } catch (RemoteException e) { Log.e(TAG, "isMultiSimSupported RemoteException", e); @@ -11637,7 +11732,7 @@ public class TelephonyManager { ITelephony service = getITelephony(); if (service != null) { return service.doesSwitchMultiSimConfigTriggerReboot(getSubId(), - getOpPackageName()); + getOpPackageName(), getFeatureId()); } } catch (RemoteException e) { Log.e(TAG, "doesSwitchMultiSimConfigTriggerReboot RemoteException", e); @@ -11671,6 +11766,114 @@ public class TelephonyManager { } /** + * Get the calling application status about carrier privileges for the subscription created + * in TelephonyManager. Used by Telephony Module for permission checking. + * + * @param uid Uid to check. + * @return any value of {@link #CARRIER_PRIVILEGE_STATUS_HAS_ACCESS}, + * {@link #CARRIER_PRIVILEGE_STATUS_NO_ACCESS}, + * {@link #CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED}, or + * {@link #CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES} + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public int getCarrierPrivilegeStatus(int uid) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getCarrierPrivilegeStatusForUid(getSubId(), uid); + } + } catch (RemoteException ex) { + Log.e(TAG, "getCarrierPrivilegeStatus RemoteException", ex); + } + return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; + } + + /** + * Returns a list of APNs set as overrides by the device policy manager via + * {@link #addDevicePolicyOverrideApn}. + * This method must only be called from the system or phone processes. + * + * @param context Context to use. + * @return {@link List} of APNs that have been set as overrides. + * @throws {@link SecurityException} if the caller is not the system or phone process. + * @hide + */ + @SystemApi + @TestApi + // TODO: add new permission tag indicating that this is system-only. + public @NonNull List<ApnSetting> getDevicePolicyOverrideApns(@NonNull Context context) { + try (Cursor cursor = context.getContentResolver().query(DPC_URI, null, null, null, null)) { + if (cursor == null) { + return Collections.emptyList(); + } + List<ApnSetting> apnList = new ArrayList<ApnSetting>(); + cursor.moveToPosition(-1); + while (cursor.moveToNext()) { + ApnSetting apn = ApnSetting.makeApnSetting(cursor); + apnList.add(apn); + } + return apnList; + } + } + + /** + * Used by the device policy manager to add a new override APN. + * This method must only be called from the system or phone processes. + * + * @param context Context to use. + * @param apnSetting The {@link ApnSetting} describing the new APN. + * @return An integer, corresponding to a primary key in a database, that allows the caller to + * modify the APN in the future via {@link #modifyDevicePolicyOverrideApn}, or + * {@link android.provider.Telephony.Carriers.INVALID_APN_ID} if the override operation + * failed. + * @throws {@link SecurityException} if the caller is not the system or phone process. + * @hide + */ + @SystemApi + @TestApi + // TODO: add new permission tag indicating that this is system-only. + public int addDevicePolicyOverrideApn(@NonNull Context context, + @NonNull ApnSetting apnSetting) { + Uri resultUri = context.getContentResolver().insert(DPC_URI, apnSetting.toContentValues()); + + int resultId = INVALID_APN_ID; + if (resultUri != null) { + try { + resultId = Integer.parseInt(resultUri.getLastPathSegment()); + } catch (NumberFormatException e) { + Rlog.e(TAG, "Failed to parse inserted override APN id: " + + resultUri.getLastPathSegment()); + } + } + return resultId; + } + + /** + * Used by the device policy manager to modify an override APN. + * This method must only be called from the system or phone processes. + * + * @param context Context to use. + * @param apnId The integer key of the APN to modify, as returned by + * {@link #addDevicePolicyOverrideApn} + * @param apnSetting The {@link ApnSetting} describing the updated APN. + * @return {@code true} if successful, {@code false} otherwise. + * @throws {@link SecurityException} if the caller is not the system or phone process. + * @hide + */ + @SystemApi + @TestApi + // TODO: add new permission tag indicating that this is system-only. + public boolean modifyDevicePolicyOverrideApn(@NonNull Context context, int apnId, + @NonNull ApnSetting apnSetting) { + return context.getContentResolver().update( + Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), + apnSetting.toContentValues(), null, null) > 0; + } + + /** * Return whether data is enabled for certain APN type. This will tell if framework will accept * corresponding network requests on a subId. * @@ -11728,6 +11931,37 @@ public class TelephonyManager { } /** + * Verifies whether the input MCC/MNC and MVNO correspond to the current carrier. + * + * @param mccmnc the carrier's mccmnc that you want to match + * @param mvnoType the mvnoType that defined in {@link ApnSetting} + * @param mvnoMatchData the MVNO match data + * @return {@code true} if input mccmnc and mvno matches with data from sim operator. + * {@code false} otherwise. + * + * {@hide} + */ + @SystemApi + public boolean isCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType, + @Nullable String mvnoMatchData) { + try { + if (!mccmnc.equals(getSimOperator())) { + Log.d(TAG, "The mccmnc does not match"); + return false; + } + ITelephony service = getITelephony(); + if (service != null) { + return service.isMvnoMatched(getSubId(), mvnoType, mvnoMatchData); + } + } catch (RemoteException ex) { + if (!isSystemProcess()) { + ex.rethrowAsRuntimeException(); + } + } + return false; + } + + /** * Set allowing mobile data during voice call. * * @param allow {@code true} if allowing using data during voice call, {@code false} if diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java index 9ff851598648..1651c8111ce8 100644 --- a/telephony/java/android/telephony/TelephonyScanManager.java +++ b/telephony/java/android/telephony/TelephonyScanManager.java @@ -16,6 +16,8 @@ package android.telephony; +import com.android.telephony.Rlog; + import static com.android.internal.util.Preconditions.checkNotNull; import android.content.Context; @@ -200,13 +202,14 @@ public final class TelephonyScanManager { */ public NetworkScan requestNetworkScan(int subId, NetworkScanRequest request, Executor executor, NetworkScanCallback callback, - String callingPackage) { + String callingPackage, String callingFeatureId) { try { ITelephony telephony = getITelephony(); if (telephony != null) { synchronized (mScanInfo) { int scanId = telephony.requestNetworkScan( - subId, request, mMessenger, new Binder(), callingPackage); + subId, request, mMessenger, new Binder(), callingPackage, + callingFeatureId); if (scanId == INVALID_SCAN_ID) { Rlog.e(TAG, "Failed to initiate network scan"); return null; diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java index 93ccba1dd996..81a09c645070 100644 --- a/telephony/java/android/telephony/UiccAccessRule.java +++ b/telephony/java/android/telephony/UiccAccessRule.java @@ -15,6 +15,8 @@ */ package android.telephony; +import com.android.telephony.Rlog; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java index f65c7b0c0c9b..6b1544376a6c 100644 --- a/telephony/java/android/telephony/VoLteServiceState.java +++ b/telephony/java/android/telephony/VoLteServiceState.java @@ -16,12 +16,12 @@ package android.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; +import com.android.telephony.Rlog; import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Rlog; /** * Contains LTE network state related information. diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java index 45b1e474b93d..9bc39a0c6ced 100644 --- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java +++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java @@ -16,7 +16,7 @@ package android.telephony.cdma; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.telephony.CellLocation; diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 034fc220cbbe..fab1bf2215af 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -28,7 +28,7 @@ import android.provider.Telephony; import android.provider.Telephony.Carriers; import android.telephony.Annotation.ApnType; import android.telephony.Annotation.NetworkType; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -1056,6 +1056,11 @@ public class ApnSetting implements Parcelable { } /** @hide */ + public boolean isEmergencyApn() { + return hasApnType(TYPE_EMERGENCY); + } + + /** @hide */ public boolean canHandleType(@ApnType int type) { if (!mCarrierEnabled) { return false; diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index 372bdf1c0f81..bff12b624ae8 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -31,7 +31,7 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.telephony.AccessNetworkConstants; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java index 11dc78a611ff..d33d3f9a5eee 100644 --- a/telephony/java/android/telephony/data/DataServiceCallback.java +++ b/telephony/java/android/telephony/data/DataServiceCallback.java @@ -22,7 +22,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.LinkProperties; import android.os.RemoteException; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.telephony.data.DataService.DataServiceProvider; import java.lang.annotation.Retention; diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java index e793979a61c9..8220b16500de 100644 --- a/telephony/java/android/telephony/data/QualifiedNetworksService.java +++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java @@ -28,7 +28,7 @@ import android.os.Message; import android.os.RemoteException; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.Annotation.ApnType; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index 16662652847d..cd3fc953f9d2 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -25,7 +25,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java index cb27f64da7fa..23d46ba09599 100644 --- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java +++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java @@ -17,17 +17,18 @@ package android.telephony.euicc; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.telephony.UiccAccessRule; + +import com.android.internal.util.Preconditions; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import com.android.internal.util.Preconditions; - /** * Information about a subscription which is downloadable to an eUICC using * {@link EuiccManager#downloadSubscription(DownloadableSubscription, boolean, PendingIntent). diff --git a/telephony/java/android/telephony/euicc/EuiccInfo.java b/telephony/java/android/telephony/euicc/EuiccInfo.java index 91ebb6ca2d45..467d2689cd3c 100644 --- a/telephony/java/android/telephony/euicc/EuiccInfo.java +++ b/telephony/java/android/telephony/euicc/EuiccInfo.java @@ -16,7 +16,7 @@ package android.telephony.euicc; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java index d6780ce107c9..30cea0e6dd59 100644 --- a/telephony/java/android/telephony/gsm/GsmCellLocation.java +++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java @@ -16,7 +16,7 @@ package android.telephony.gsm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.telephony.CellLocation; diff --git a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java index 9f09d7a93a82..d53a2e6591a2 100644 --- a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java +++ b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 87e53919c2a1..a7d553b60abf 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -18,9 +18,10 @@ package android.telephony.ims; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -40,10 +41,11 @@ import java.util.ArrayList; import java.util.List; /** - * Parcelable object to handle IMS call profile. - * It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111. - * It provides the service and call type, the additional information related to the call. - * + * A Parcelable object to handle the IMS call profile, which provides the service, call type, and + * additional information related to the call. + * <p> + * See the following specifications for more information about this class: GSMA IR.92/IR.94, + * 3GPP TS 24.229/TS 26.114/TS26.111. * @hide */ @SystemApi @@ -151,12 +153,13 @@ public final class ImsCallProfile implements Parcelable { */ public static final String EXTRA_CONFERENCE_AVAIL = "conference_avail"; - // Extra string for internal use only. OEMs should not use - // this for packing extras. /** + * Extra key used to store a Bundle containing proprietary extras to send to the ImsService. + * Use {@link #getProprietaryCallExtras()} instead. * @hide */ - public static final String EXTRA_OEM_EXTRAS = "OemCallExtras"; + @TestApi + public static final String EXTRA_OEM_EXTRAS = "android.telephony.ims.extra.OEM_EXTRAS"; /** * Rule for originating identity (number) presentation, MO/MT. @@ -291,15 +294,30 @@ public final class ImsCallProfile implements Parcelable { * updateImsCallRatFromExtras(Bundle)} to determine whether to set the * {@link android.telecom.TelecomManager#EXTRA_CALL_NETWORK_TYPE} extra value and * {@link android.telecom.Connection#PROPERTY_WIFI} property on a connection. + * @deprecated the constants associated with this extra are hidden, instead use + * {@link #EXTRA_CALL_NETWORK_TYPE}. */ + @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech"; /** + * Extra key with an {@code int} value which can be set in {@link #setCallExtraInt(String, int)} + * to indicate the network type used for a call. + * <p> + * Valid values are defined by {@code TelephonyManager.NETWORK_TYPE_*} constants. An example may + * be {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}. + */ + public static final String EXTRA_CALL_NETWORK_TYPE = + "android.telephony.ims.extra.CALL_NETWORK_TYPE"; + + /** * Similar to {@link #EXTRA_CALL_RAT_TYPE}, except with a lowercase 'c'. Used to ensure * compatibility with modems that are non-compliant with the {@link #EXTRA_CALL_RAT_TYPE} * extra key. Should be removed when the non-compliant modems are fixed. * @hide + * @deprecated Use {@link #EXTRA_CALL_NETWORK_TYPE} instead. */ + @Deprecated public static final String EXTRA_CALL_RAT_TYPE_ALT = "callRadioTech"; /** @hide */ @@ -679,6 +697,18 @@ public final class ImsCallProfile implements Parcelable { return mCallExtras; } + /** + * Get the proprietary extras set for this ImsCallProfile. + * @return A {@link Bundle} containing proprietary call extras that were not set by the + * platform. + */ + public @Nullable Bundle getProprietaryCallExtras() { + if (mCallExtras == null) { + return null; + } + return mCallExtras.getBundle(EXTRA_OEM_EXTRAS); + } + public ImsStreamMediaProfile getMediaProfile() { return mMediaProfile; } diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java index 5adc99e11478..1b583fd29965 100644 --- a/telephony/java/android/telephony/ims/ImsCallSession.java +++ b/telephony/java/android/telephony/ims/ImsCallSession.java @@ -25,8 +25,6 @@ import android.util.Log; import com.android.ims.internal.IImsCallSession; import com.android.ims.internal.IImsVideoCallProvider; -import java.util.Objects; - /** * Provides the call initiation/termination, and media exchange between two IMS endpoints. * It directly communicates with IMS service which implements the IMS protocol behavior. @@ -346,7 +344,7 @@ public class ImsCallSession { } /** - * Called when an {@link ImsCallSession} may handover from one radio technology to another. + * Called when an {@link ImsCallSession} may handover from one network type to another. * For example, the session may handover from WIFI to LTE if conditions are right. * <p> * If handover is attempted, @@ -355,24 +353,24 @@ public class ImsCallSession { * called to indicate the success or failure of the handover. * * @param session IMS session object - * @param srcAccessTech original access technology - * @param targetAccessTech new access technology + * @param srcNetworkType original network type + * @param targetNetworkType new network type */ - public void callSessionMayHandover(ImsCallSession session, int srcAccessTech, - int targetAccessTech) { + public void callSessionMayHandover(ImsCallSession session, int srcNetworkType, + int targetNetworkType) { // no-op } /** - * Called when session access technology changes + * Called when session network type changes * * @param session IMS session object - * @param srcAccessTech original access technology - * @param targetAccessTech new access technology + * @param srcNetworkType original network type + * @param targetNetworkType new network type * @param reasonInfo */ public void callSessionHandover(ImsCallSession session, - int srcAccessTech, int targetAccessTech, + int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo) { // no-op } @@ -381,12 +379,12 @@ public class ImsCallSession { * Called when session access technology change fails * * @param session IMS session object - * @param srcAccessTech original access technology - * @param targetAccessTech new access technology + * @param srcNetworkType original access technology + * @param targetNetworkType new access technology * @param reasonInfo handover failure reason */ public void callSessionHandoverFailed(ImsCallSession session, - int srcAccessTech, int targetAccessTech, + int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo) { // no-op } @@ -1303,20 +1301,19 @@ public class ImsCallSession { /** * Notifies of a case where a {@link ImsCallSession} may * potentially handover from one radio technology to another. - * @param srcAccessTech The source radio access technology; one of the access technology - * constants defined in {@link android.telephony.ServiceState}. For - * example - * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}. - * @param targetAccessTech The target radio access technology; one of the access technology - * constants defined in {@link android.telephony.ServiceState}. For - * example - * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}. + * @param srcNetworkType The source network type; one of the network type constants defined + * in {@link android.telephony.TelephonyManager}. For example + * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}. + * @param targetNetworkType The target radio access technology; one of the network type + * constants defined in {@link android.telephony.TelephonyManager}. + * For example + * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}. */ @Override - public void callSessionMayHandover(int srcAccessTech, int targetAccessTech) { + public void callSessionMayHandover(int srcNetworkType, int targetNetworkType) { if (mListener != null) { - mListener.callSessionMayHandover(ImsCallSession.this, srcAccessTech, - targetAccessTech); + mListener.callSessionMayHandover(ImsCallSession.this, srcNetworkType, + targetNetworkType); } } @@ -1324,11 +1321,11 @@ public class ImsCallSession { * Notifies of handover information for this call */ @Override - public void callSessionHandover(int srcAccessTech, int targetAccessTech, + public void callSessionHandover(int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo) { if (mListener != null) { - mListener.callSessionHandover(ImsCallSession.this, srcAccessTech, - targetAccessTech, reasonInfo); + mListener.callSessionHandover(ImsCallSession.this, srcNetworkType, + targetNetworkType, reasonInfo); } } @@ -1336,11 +1333,11 @@ public class ImsCallSession { * Notifies of handover failure info for this call */ @Override - public void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech, + public void callSessionHandoverFailed(int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo) { if (mListener != null) { - mListener.callSessionHandoverFailed(ImsCallSession.this, srcAccessTech, - targetAccessTech, reasonInfo); + mListener.callSessionHandoverFailed(ImsCallSession.this, srcNetworkType, + targetNetworkType, reasonInfo); } } diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java index e11886f2bea5..025721c89f70 100644 --- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java +++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java @@ -17,10 +17,13 @@ package android.telephony.ims; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.RemoteException; +import android.telephony.Annotation; import android.telephony.CallQuality; +import android.telephony.ServiceState; import android.telephony.ims.aidl.IImsCallSessionListener; import android.telephony.ims.stub.ImsCallSessionImplBase; @@ -476,11 +479,27 @@ public class ImsCallSessionListener { * @param targetAccessTech The target radio access technology; one of the access technology * constants defined in {@link android.telephony.ServiceState}. For example * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}. + * @deprecated Uses hidden constants for radio access technology, use + * {@link #onMayHandover(int, int)} instead. */ - public void callSessionMayHandover(int srcAccessTech, int targetAccessTech) - { + @Deprecated + public void callSessionMayHandover(int srcAccessTech, int targetAccessTech) { + // Use new API internally. + onMayHandover(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech), + ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech)); + } + + /** + * Notify the framework that the associated {@link ImsCallSession} may handover from one network + * type to another. + * + * @param srcNetworkType The source network type. + * @param targetNetworkType The target network type. + */ + public void onMayHandover(@Annotation.NetworkType int srcNetworkType, + @Annotation.NetworkType int targetNetworkType) { try { - mListener.callSessionMayHandover(srcAccessTech, targetAccessTech); + mListener.callSessionMayHandover(srcNetworkType, targetNetworkType); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -494,11 +513,29 @@ public class ImsCallSessionListener { * @param targetAccessTech new access technology, defined in * {@link android.telephony.ServiceState}. * @param reasonInfo The {@link ImsReasonInfo} associated with this handover. + * @deprecated Uses hidden radio access technology constants, use + * {@link #onHandover(int, int, ImsReasonInfo)} instead. */ + @Deprecated public void callSessionHandover(int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo) { + // Use new API internally. + onHandover(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech), + ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo); + } + + /** + * Notify the framework that the associated {@link ImsCallSession} has handed over from one + * network type to another. + * + * @param srcNetworkType original network type. + * @param targetNetworkType target network type after handover.. + * @param reasonInfo An optional {@link ImsReasonInfo} associated with this handover. + */ + public void onHandover(@Annotation.NetworkType int srcNetworkType, + @Annotation.NetworkType int targetNetworkType, @Nullable ImsReasonInfo reasonInfo) { try { - mListener.callSessionHandover(srcAccessTech, targetAccessTech, reasonInfo); + mListener.callSessionHandover(srcNetworkType, targetNetworkType, reasonInfo); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -510,11 +547,28 @@ public class ImsCallSessionListener { * @param srcAccessTech original access technology * @param targetAccessTech new access technology * @param reasonInfo An {@link ImsReasonInfo} detailing the reason for the failure. + * @deprecated Uses hidden radio access technology constants, use + * {@link #onHandoverFailed(int, int, ImsReasonInfo)} instead */ + @Deprecated public void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo) { + // Use new API internally. + onHandoverFailed(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech), + ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo); + } + + /** + * The IMS call session's access technology change has failed.. + * + * @param srcNetworkType original network type. + * @param targetNetworkType target network type that the handover failed for. + * @param reasonInfo An {@link ImsReasonInfo} detailing the reason for the failure. + */ + public void onHandoverFailed(@Annotation.NetworkType int srcNetworkType, + @Annotation.NetworkType int targetNetworkType, @NonNull ImsReasonInfo reasonInfo) { try { - mListener.callSessionHandoverFailed(srcAccessTech, targetAccessTech, reasonInfo); + mListener.callSessionHandoverFailed(srcNetworkType, targetNetworkType, reasonInfo); } catch (RemoteException e) { throw new RuntimeException(e); } diff --git a/telephony/java/android/telephony/ims/ImsConferenceState.java b/telephony/java/android/telephony/ims/ImsConferenceState.java index 8d2049b97138..abfee61930ed 100644 --- a/telephony/java/android/telephony/ims/ImsConferenceState.java +++ b/telephony/java/android/telephony/ims/ImsConferenceState.java @@ -24,7 +24,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.telecom.Call; import android.telecom.Connection; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.util.Log; import java.util.HashMap; diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java index 39af2e770882..cb3f0f92625e 100644 --- a/telephony/java/android/telephony/ims/ImsException.java +++ b/telephony/java/android/telephony/ims/ImsException.java @@ -30,10 +30,7 @@ import java.lang.annotation.RetentionPolicy; /** * This class defines an IMS-related exception that has been thrown while interacting with a * device or carrier provided ImsService implementation. - * @hide */ -@SystemApi -@TestApi public final class ImsException extends Exception { /** @@ -83,7 +80,10 @@ public final class ImsException extends Exception { /** * A new {@link ImsException} with an unspecified {@link ImsErrorCode} code. * @param message an optional message to detail the error condition more specifically. + * @hide */ + @SystemApi + @TestApi public ImsException(@Nullable String message) { super(getMessage(message, CODE_ERROR_UNSPECIFIED)); } @@ -91,7 +91,10 @@ public final class ImsException extends Exception { /** * A new {@link ImsException} that includes an {@link ImsErrorCode} error code. * @param message an optional message to detail the error condition more specifically. + * @hide */ + @SystemApi + @TestApi public ImsException(@Nullable String message, @ImsErrorCode int code) { super(getMessage(message, code)); mCode = code; @@ -102,7 +105,10 @@ public final class ImsException extends Exception { * {@link Throwable} that contains the original error that was thrown to lead to this Exception. * @param message an optional message to detail the error condition more specifically. * @param cause the {@link Throwable} that caused this {@link ImsException} to be created. + * @hide */ + @SystemApi + @TestApi public ImsException(@Nullable String message, @ImsErrorCode int code, @Nullable Throwable cause) { super(getMessage(message, code), cause); diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java index dcb9c9d5ec27..136a83e2eec9 100644 --- a/telephony/java/android/telephony/ims/ImsExternalCallState.java +++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java @@ -24,7 +24,7 @@ import android.annotation.TestApi; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 5fd0af564d34..c66672f13129 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -23,6 +23,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressAutoDoc; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; @@ -56,10 +58,7 @@ import java.util.function.Consumer; * associated subscription. * * @see #createForSubscriptionId(int) - * @hide */ -@SystemApi -@TestApi public class ImsMmTelManager implements RegistrationManager { /** @@ -94,9 +93,11 @@ public class ImsMmTelManager implements RegistrationManager { * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback) * @see #unregisterImsRegistrationCallback(RegistrationCallback) * @deprecated Use {@link RegistrationManager.RegistrationCallback} instead. + * @hide */ // Do not add to this class, add to RegistrationManager.RegistrationCallback instead. @Deprecated + @SystemApi @TestApi public static class RegistrationCallback extends RegistrationManager.RegistrationCallback { /** @@ -141,7 +142,7 @@ public class ImsMmTelManager implements RegistrationManager { /** * Receives IMS capability status updates from the ImsService. This information is also - * available via the {@link #isAvailable(int, int)} method below. + * available via the {@see #isAvailable(int, int)} method below. * * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback) * @see #unregisterMmTelCapabilityCallback(CapabilityCallback) @@ -190,7 +191,7 @@ public class ImsMmTelManager implements RegistrationManager { * If unavailable, the feature is not able to support the unavailable capability at this * time. * - * This information can also be queried using the {@link #isAvailable(int, int)} API. + * This information can also be queried using the {@see #isAvailable(int, int)} API. * * @param capabilities The new availability of the capabilities. */ @@ -218,8 +219,20 @@ public class ImsMmTelManager implements RegistrationManager { * * @param subId The ID of the subscription that this ImsMmTelManager will use. * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList() + * + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges + * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). + * * @throws IllegalArgumentException if the subscription is invalid. + * */ + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE + }) + @SuppressLint("ManagerLookup") public static @NonNull ImsMmTelManager createForSubscriptionId(int subId) { if (!SubscriptionManager.isValidSubscriptionId(subId)) { throw new IllegalArgumentException("Invalid subscription ID"); @@ -258,8 +271,10 @@ public class ImsMmTelManager implements RegistrationManager { * reason. * @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor, * RegistrationManager.RegistrationCallback)} instead. + * @hide */ @Deprecated + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor, @NonNull RegistrationCallback c) throws ImsException { @@ -284,9 +299,20 @@ public class ImsMmTelManager implements RegistrationManager { } } - /**{@inheritDoc}*/ + /** + * + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges + * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). + * + * {@inheritDoc} + * + */ @Override - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor, @NonNull RegistrationManager.RegistrationCallback c) throws ImsException { if (c == null) { @@ -317,8 +343,10 @@ public class ImsMmTelManager implements RegistrationManager { * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) * @deprecated Use {@link #unregisterImsRegistrationCallback( * RegistrationManager.RegistrationCallback)}. + * @hide */ @Deprecated + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) { if (c == null) { @@ -331,9 +359,20 @@ public class ImsMmTelManager implements RegistrationManager { } } - /**{@inheritDoc}*/ + /** + * + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges + * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). + * Access by profile owners is deprecated and will be removed in a future release. + * + *{@inheritDoc} + */ @Override - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterImsRegistrationCallback( @NonNull RegistrationManager.RegistrationCallback c) { if (c == null) { @@ -346,9 +385,13 @@ public class ImsMmTelManager implements RegistrationManager { } } - /**{@inheritDoc}*/ + /** + * {@inheritDoc} + * @hide + */ @Override - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SystemApi @TestApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull @CallbackExecutor Executor executor, @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) { if (stateCallback == null) { @@ -369,9 +412,19 @@ public class ImsMmTelManager implements RegistrationManager { } } - /**{@inheritDoc}*/ + /** + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges + * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). + * Access by profile owners is deprecated and will be removed in a future release. + * + *{@inheritDoc} + */ @Override - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor, @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback) { @@ -397,12 +450,25 @@ public class ImsMmTelManager implements RegistrationManager { /** * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service * availability updates for the subscription specified in - * {@link #createForSubscriptionId(int)}. The method {@link #isAvailable(int, int)} + * {@link #createForSubscriptionId(int)}. The method {@see #isAvailable(int, int)} * can also be used to query this information at any time. * * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to * subscription changed events and call * {@link #unregisterMmTelCapabilityCallback(CapabilityCallback)} to clean up. + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. * * When the callback is registered, it will initiate the callback c to be called with the * current capabilities. @@ -418,7 +484,10 @@ public class ImsMmTelManager implements RegistrationManager { * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor, @NonNull CapabilityCallback c) throws ImsException { if (c == null) { @@ -450,10 +519,27 @@ public class ImsMmTelManager implements RegistrationManager { * When the subscription associated with this callback is removed (SIM removed, ESIM swap, * etc...), this callback will automatically be removed. If this method is called for an * inactive subscription, it will result in a no-op. + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @param c The MmTel {@link CapabilityCallback} to be removed. * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) { if (c == null) { throw new IllegalArgumentException("Must include a non-null RegistrationCallback."); @@ -475,6 +561,19 @@ public class ImsMmTelManager implements RegistrationManager { * <p> * Note: If the carrier configuration for advanced calling is not editable or hidden, this * method will always return the default value. + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. * * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL @@ -486,7 +585,10 @@ public class ImsMmTelManager implements RegistrationManager { * active (SIM is not inserted, ESIM inactive) or invalid. * @return true if the user's setting for advanced calling is enabled, false otherwise. */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isAdvancedCallingSettingEnabled() { try { return getITelephony().isAdvancedCallingSettingEnabled(mSubId); @@ -524,8 +626,10 @@ public class ImsMmTelManager implements RegistrationManager { * @see #isAdvancedCallingSettingEnabled() * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. + * @hide */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi @TestApi public void setAdvancedCallingSettingEnabled(boolean isEnabled) { try { getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled); @@ -556,13 +660,15 @@ public class ImsMmTelManager implements RegistrationManager { * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} * @param capability The IMS MmTel capability to query, can be one of the following: * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO, + * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS} * @return {@code true} if the MmTel IMS capability is capable for this subscription, false * otherwise. + * @hide */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SystemApi @TestApi public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) { try { @@ -583,12 +689,14 @@ public class ImsMmTelManager implements RegistrationManager { * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} * @param capability The IMS MmTel capability to query, can be one of the following: * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO, + * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS} * @return {@code true} if the MmTel IMS capability is available for this subscription, false * otherwise. + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) { @@ -613,7 +721,9 @@ public class ImsMmTelManager implements RegistrationManager { * capability is supported on this carrier network for the transport specified. * @throws ImsException if the subscription is no longer valid or the IMS service is not * available. + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @AccessNetworkConstants.TransportType int transportType, @@ -642,12 +752,32 @@ public class ImsMmTelManager implements RegistrationManager { /** * The user's setting for whether or not they have enabled the "Video Calling" setting. * + * <p> + * Note: If the carrier configuration for advanced calling is not editable or hidden, this + * method will always return the default value. + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @return true if the user’s “Video Calling” setting is currently enabled. * @see #setVtSettingEnabled(boolean) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). public boolean isVtSettingEnabled() { try { return getITelephony().isVtSettingEnabled(mSubId); @@ -669,7 +799,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #isVtSettingEnabled() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean isEnabled) { try { @@ -689,11 +821,28 @@ public class ImsMmTelManager implements RegistrationManager { /** * @return true if the user's setting for Voice over WiFi is enabled and false if it is not. * + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #setVoWiFiSettingEnabled(boolean) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled() { try { return getITelephony().isVoWiFiSettingEnabled(mSubId); @@ -716,7 +865,9 @@ public class ImsMmTelManager implements RegistrationManager { * active (SIM is not inserted, ESIM inactive) or invalid. * @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise= * @see #isVoWiFiSettingEnabled() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean isEnabled) { try { @@ -736,13 +887,30 @@ public class ImsMmTelManager implements RegistrationManager { /** * Returns the user's voice over WiFi roaming setting associated with the current subscription. * + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @return true if the user's setting for Voice over WiFi while roaming is enabled, false * if disabled. * @see #setVoWiFiRoamingSettingEnabled(boolean) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiRoamingSettingEnabled() { try { return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId); @@ -766,7 +934,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #isVoWiFiRoamingSettingEnabled() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) { try { @@ -796,7 +966,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #setVoWiFiSettingEnabled(boolean) + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiNonPersistent(boolean isCapable, int mode) { try { @@ -816,6 +988,20 @@ public class ImsMmTelManager implements RegistrationManager { /** * Returns the user's voice over WiFi Roaming mode setting associated with the device. * + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @return The Voice over WiFi Mode preference set by the user, which can be one of the @@ -825,7 +1011,10 @@ public class ImsMmTelManager implements RegistrationManager { * - {@link #WIFI_MODE_WIFI_PREFERRED} * @see #setVoWiFiSettingEnabled(boolean) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public @WiFiCallingMode int getVoWiFiModeSetting() { try { return getITelephony().getVoWiFiModeSetting(mSubId); @@ -851,7 +1040,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #getVoWiFiModeSetting() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(@WiFiCallingMode int mode) { try { @@ -880,7 +1071,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #setVoWiFiRoamingSettingEnabled(boolean) + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @WiFiCallingMode int getVoWiFiRoamingModeSetting() { try { @@ -909,7 +1102,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #getVoWiFiRoamingModeSetting() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) { try { @@ -936,7 +1131,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @param isEnabled if true RTT should be enabled during calls made on this subscription. + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean isEnabled) { try { @@ -956,12 +1153,29 @@ public class ImsMmTelManager implements RegistrationManager { /** * @return true if TTY over VoLTE is supported * + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see android.telecom.TelecomManager#getCurrentTtyMode * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isTtyOverVolteEnabled() { try { return getITelephony().isTtyOverVolteEnabled(mSubId); @@ -988,7 +1202,9 @@ public class ImsMmTelManager implements RegistrationManager { * specified when the service state has been retrieved from the IMS service. * @throws ImsException if the IMS service associated with this subscription is not available or * the IMS service is not available. + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull @CallbackExecutor Executor executor, @NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException { diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java index 0c8dba664b0a..5aa37bba7efe 100644 --- a/telephony/java/android/telephony/ims/ImsRcsManager.java +++ b/telephony/java/android/telephony/ims/ImsRcsManager.java @@ -28,6 +28,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.AccessNetworkConstants; +import android.telephony.SubscriptionManager; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsRcsController; import android.telephony.ims.feature.ImsFeature; @@ -35,6 +36,8 @@ import android.telephony.ims.feature.RcsFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; +import com.android.internal.telephony.IIntegerConsumer; + import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -154,9 +157,20 @@ public class ImsRcsManager implements RegistrationManager { if (executor == null) { throw new IllegalArgumentException("Must include a non-null Executor."); } + + IImsRcsController imsRcsController = getIImsRcsController(); + if (imsRcsController == null) { + Log.e(TAG, "Register registration callback: IImsRcsController is null"); + throw new ImsException("Cannot find remote IMS service", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + c.setExecutor(executor); - throw new UnsupportedOperationException("registerImsRegistrationCallback is not" - + "supported."); + try { + imsRcsController.registerImsRegistrationCallback(mSubId, c.getBinder()); + } catch (RemoteException | IllegalStateException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } } /**{@inheritDoc}*/ @@ -167,8 +181,18 @@ public class ImsRcsManager implements RegistrationManager { if (c == null) { throw new IllegalArgumentException("Must include a non-null RegistrationCallback."); } - throw new UnsupportedOperationException("unregisterImsRegistrationCallback is not" - + "supported."); + + IImsRcsController imsRcsController = getIImsRcsController(); + if (imsRcsController == null) { + Log.e(TAG, "Unregister registration callback: IImsRcsController is null"); + throw new IllegalStateException("Cannot find remote IMS service"); + } + + try { + imsRcsController.unregisterImsRegistrationCallback(mSubId, c.getBinder()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } } /**{@inheritDoc}*/ @@ -182,8 +206,23 @@ public class ImsRcsManager implements RegistrationManager { if (executor == null) { throw new IllegalArgumentException("Must include a non-null Executor."); } - throw new UnsupportedOperationException("getRegistrationState is not" - + "supported."); + + IImsRcsController imsRcsController = getIImsRcsController(); + if (imsRcsController == null) { + Log.e(TAG, "Get registration state error: IImsRcsController is null"); + throw new IllegalStateException("Cannot find remote IMS service"); + } + + try { + imsRcsController.getImsRcsRegistrationState(mSubId, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> stateCallback.accept(result)); + } + }); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } } /**{@inheritDoc}*/ @@ -198,10 +237,25 @@ public class ImsRcsManager implements RegistrationManager { if (executor == null) { throw new IllegalArgumentException("Must include a non-null Executor."); } - throw new UnsupportedOperationException("getRegistrationTransportType is not" - + "supported."); - } + IImsRcsController imsRcsController = getIImsRcsController(); + if (imsRcsController == null) { + Log.e(TAG, "Get registration transport type error: IImsRcsController is null"); + throw new IllegalStateException("Cannot find remote IMS service"); + } + + try { + imsRcsController.getImsRcsRegistrationTransportType(mSubId, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> transportTypeCallback.accept(result)); + } + }); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } /** * Registers an {@link AvailabilityCallback} with the system, which will provide RCS diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java index f4b2cef73a44..0d6b31d349e1 100644 --- a/telephony/java/android/telephony/ims/ImsReasonInfo.java +++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java index 6b728599c7d3..2d2e63812fad 100644 --- a/telephony/java/android/telephony/ims/ImsSsData.java +++ b/telephony/java/android/telephony/ims/ImsSsData.java @@ -22,7 +22,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java index 77bd98411037..9cce95fc67f8 100644 --- a/telephony/java/android/telephony/ims/ImsSsInfo.java +++ b/telephony/java/android/telephony/ims/ImsSsInfo.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java index b7ab0a09a1cb..b70fd649ab79 100644 --- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java +++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java @@ -19,7 +19,7 @@ package android.telephony.ims; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/android/telephony/ims/ImsVideoCallProvider.java b/telephony/java/android/telephony/ims/ImsVideoCallProvider.java index 270e693c8825..569c6d5a4e4d 100644 --- a/telephony/java/android/telephony/ims/ImsVideoCallProvider.java +++ b/telephony/java/android/telephony/ims/ImsVideoCallProvider.java @@ -18,7 +18,7 @@ package android.telephony.ims; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Handler; import android.os.Looper; diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index e16085e30465..aa4f77d09212 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -26,15 +26,15 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.WorkerThread; import android.content.Context; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.ims.aidl.IImsConfigCallback; import android.telephony.ims.feature.MmTelFeature; +import android.telephony.ims.feature.RcsFeature; import android.telephony.ims.stub.ImsConfigImplBase; import android.telephony.ims.stub.ImsRegistrationImplBase; @@ -85,6 +85,11 @@ public class ProvisioningManager { "STRING_QUERY_RESULT_ERROR_NOT_READY"; /** + * There is no existing configuration for the queried provisioning key. + */ + public static final int PROVISIONING_RESULT_UNKNOWN = -1; + + /** * The integer result of provisioning for the queried key is disabled. */ public static final int PROVISIONING_VALUE_DISABLED = 0; @@ -95,6 +100,313 @@ public class ProvisioningManager { public static final int PROVISIONING_VALUE_ENABLED = 1; + // Inheriting values from ImsConfig for backwards compatibility. + /** + * AMR CODEC Mode Value set, 0-7 in comma separated sequence. + * <p> + * This corresponds to the {@code mode-set} parameter for the AMR codec. + * See 3GPP TS 26.101 Table 1A for more information. + * <p> + * <UL> + * <LI>0 - AMR 4.75 kbit/s</LI> + * <LI>1 - AMR 5.15 kbit/s</LI> + * <LI>2 - AMR 5.90 kbit/s</LI> + * <LI>3 - AMR 6.70 kbit/s (PDC-EFR)</LI> + * <LI>4 - AMR 7.40 kbit/s (TDMA-EFR)</LI> + * <LI>5 - AMR 7.95 kbit/s</LI> + * <LI>6 - AMR 10.2 kbit/s</LI> + * <LI>7 - AMR 12.2 kbit/s (GSM-EFR)</LI> + * </UL> + * <p> + * Value is in String format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0; + + /** + * Wide Band AMR CODEC Mode Value set,0-7 in comma separated sequence. + * <p> + * This corresponds to the {@code mode-set} parameter for the AMR wideband codec. + * See 3GPP TS 26.101 Table 1A for more information. + * <p> + * <UL> + * <LI>0 - AMR 4.75 kbit/s</LI> + * <LI>1 - AMR 5.15 kbit/s</LI> + * <LI>2 - AMR 5.90 kbit/s</LI> + * <LI>3 - AMR 6.70 kbit/s (PDC-EFR)</LI> + * <LI>4 - AMR 7.40 kbit/s (TDMA-EFR)</LI> + * <LI>5 - AMR 7.95 kbit/s</LI> + * <LI>6 - AMR 10.2 kbit/s</LI> + * <LI>7 - AMR 12.2 kbit/s (GSM-EFR)</LI> + * </UL> + * <p> + * Value is in String format. + * @see #setProvisioningStringValue(int, String) + * @see #getProvisioningStringValue(int) + */ + public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1; + + /** + * SIP Session Timer value (seconds). + * <p> + * See RFC4028 for more information. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_SESSION_TIMER_SEC = 2; + + /** + * Minimum SIP Session Expiration Timer in (seconds). + * <p> + * See RFC4028 for more information. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3; + + /** + * SIP_INVITE cancellation time out value (in milliseconds). Integer format. + * <p> + * See RFC4028 for more information. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4; + + /** + * Delay time when an iRAT transitions from eHRPD/HRPD/1xRTT to LTE. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5; + + /** + * Silent redial status of Enabled (True), or Disabled (False). + * Value is in boolean format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_ENABLE_SILENT_REDIAL = 6; + + /** + * An integer key representing the SIP T1 timer value in milliseconds for the associated + * subscription. + * <p> + * The SIP T1 timer is an estimate of the round-trip time and will retransmit + * INVITE transactions that are longer than T1 milliseconds over unreliable transports, doubling + * the time before retransmission every time there is no response. See RFC3261, section 17.1.1.1 + * for more details. + * <p> + * The value is an integer. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_T1_TIMER_VALUE_MS = 7; + + /** + * SIP T2 timer value in milliseconds. See RFC 3261 for information. + * <p> + * The T2 timer is the maximum retransmit interval for non-INVITE requests and INVITE responses. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_T2_TIMER_VALUE_MS = 8; + + /** + * SIP TF timer value in milliseconds. See RFC 3261 for information. + * <p> + * The TF timer is the non-INVITE transaction timeout timer. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_TF_TIMER_VALUE_MS = 9; + + /** + * An integer key representing the voice over LTE (VoLTE) provisioning status for the + * associated subscription. Determines whether the user can register for voice services over + * LTE. + * <p> + * Use {@link #PROVISIONING_VALUE_ENABLED} to enable VoLTE provisioning and + * {@link #PROVISIONING_VALUE_DISABLED} to disable VoLTE provisioning. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_VOLTE_PROVISIONING_STATUS = 10; + + /** + * An integer key representing the video telephony (VT) provisioning status for the + * associated subscription. Determines whether the user can register for video services over + * LTE. + * <p> + * Use {@link #PROVISIONING_VALUE_ENABLED} to enable VT provisioning and + * {@link #PROVISIONING_VALUE_DISABLED} to disable VT provisioning. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_VT_PROVISIONING_STATUS = 11; + + /** + * Domain Name for the device to populate the request URI for REGISTRATION. + * Value is in String format. + * @see #setProvisioningStringValue(int, String) + * @see #getProvisioningStringValue(int) + */ + public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; + + /** + * Device Outgoing SMS based on either 3GPP or 3GPP2 standards. + * Value is in Integer format. + * Valid values are {@link #SMS_FORMAT_3GPP} and {@link #SMS_FORMAT_3GPP2}. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SMS_FORMAT = 13; + + /** + * Value used with {@link #KEY_SMS_FORMAT} to indicate 3GPP2 SMS format is used. + * See {@link android.telephony.SmsMessage#FORMAT_3GPP2} for more information. + */ + public static final int SMS_FORMAT_3GPP2 = 0; + + /** + * Value used with {@link #KEY_SMS_FORMAT} to indicate 3GPP SMS format is used. + * See {@link android.telephony.SmsMessage#FORMAT_3GPP} for more information. + */ + public static final int SMS_FORMAT_3GPP = 1; + + /** + * Turns SMS over IMS ON/OFF on the device. + * Value is in Integer format. ON (1), OFF(0). + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SMS_OVER_IP_ENABLED = 14; + + /** + * An integer key associated with the carrier configured SIP PUBLISH timer, which dictates the + * expiration time in seconds for published online availability in RCS presence. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; + + /** + * An integer key associated with the carrier configured expiration time in seconds for + * RCS presence published offline availability in RCS presence. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; + + /** + * An integer key associated with whether or not capability discovery is provisioned for this + * subscription. Any capability requests will be ignored by the RCS service. + * <p> + * The value is an integer, either {@link #PROVISIONING_VALUE_DISABLED} if capability + * discovery is disabled or {@link #PROVISIONING_VALUE_ENABLED} if capability discovery is + * enabled. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17; + + /** + * An integer key associated with the period of time the capability information of each contact + * is cached on the device. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC = 18; + + /** + * An integer key associated with the period of time in seconds that the availability + * information of a contact is cached on the device. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; + + /** + * An integer key associated with the carrier configured interval in seconds expected between + * successive capability polling attempts. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC = 20; + + /** + * An integer key representing the minimum time allowed between two consecutive presence publish + * messages from the device. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; + + /** + * An integer key associated with the maximum number of MDNs contained in one SIP Request + * Contained List (RCS) used to retrieve the RCS capabilities of the contacts book. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22; + + /** + * An integer associated with the expiration timer used during the SIP subscription of a + * Request Contained List (RCL), which is used to retrieve the RCS capabilities of the contact + * book. + * <p> + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23; + + /** + * Applies compression to LIST Subscription. + * Value is in Integer format. Enable (1), Disable(0). + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24; + + /** + * An integer key representing the RCS enhanced address book (EAB) provisioning status for the + * associated subscription. Determines whether or not SIP OPTIONS or presence will be used to + * retrieve RCS capabilities for the user's contacts. + * <p> + * Use {@link #PROVISIONING_VALUE_ENABLED} to enable EAB provisioning and + * {@link #PROVISIONING_VALUE_DISABLED} to disable EAB provisioning. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_EAB_PROVISIONING_STATUS = 25; + /** * Override the user-defined WiFi Roaming enabled setting for this subscription, defined in * {@link SubscriptionManager#WFC_ROAMING_ENABLED_CONTENT_URI}, for the purposes of provisioning @@ -121,6 +433,349 @@ public class ProvisioningManager { public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; /** + * Enable voice over wifi. Enabled (1), or Disabled (0). + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28; + + /** + * Mobile data enabled. + * Value is in Integer format. On (1), OFF(0). + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_MOBILE_DATA_ENABLED = 29; + + /** + * VoLTE user opted in status. + * Value is in Integer format. Opted-in (1) Opted-out (0). + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30; + + /** + * Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO). + * Value is in String format. + */ + public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31; + + /** + * Keep Alive Enabled for SIP. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32; + + /** + * Registration retry Base Time value in seconds. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; + + /** + * Registration retry Max Time value in seconds. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34; + + /** + * Smallest RTP port for speech codec. + * Value is in integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + + public static final int KEY_RTP_SPEECH_START_PORT = 35; + + /** + * Largest RTP port for speech code. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RTP_SPEECH_END_PORT = 36; + + /** + * SIP Timer A's value in milliseconds. Timer A is the INVITE request retransmit interval (in + * milliseconds), for UDP only. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37; + + /** + * SIP Timer B's value in milliseconds. Timer B is the wait time for INVITE message to be, + * in milliseconds. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38; + + /** + * SIP Timer D's value in milliseconds. Timer D is the wait time for response retransmits of + * the invite client transactions, in milliseconds. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39; + + /** + * SIP Timer E's value in milliseconds. Timer E is the value Non-INVITE request retransmit + * interval (in milliseconds), for UDP only. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40; + + /** + * SIP Timer F's value in milliseconds. Timer F is the Non-INVITE transaction timeout timer, + * in milliseconds. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41; + + /** + * SIP Timer G's value in milliseconds. Timer G is the value of INVITE response + * retransmit interval. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42; + + /** + * SIP Timer H's value in milliseconds. Timer H is the value of wait time for + * ACK receipt. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43; + + /** + * SIP Timer I's value in milliseconds. Timer I is the value of wait time for + * ACK retransmits. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44; + + /** + * SIP Timer J's value in milliseconds. Timer J is the value of wait time for + * non-invite request retransmission. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45; + + /** + * SIP Timer K's value in milliseconds. Timer K is the value of wait time for + * non-invite response retransmits. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46; + + /** + * AMR WB octet aligned dynamic payload type. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47; + + /** + * AMR WB bandwidth efficient payload type. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48; + + /** + * AMR octet aligned dynamic payload type. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49; + + /** + * AMR bandwidth efficient payload type. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50; + + /** + * DTMF WB payload type. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51; + + /** + * DTMF NB payload type. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52; + + /** + * AMR Default encoding mode. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53; + + /** + * SMS Public Service Identity. + * Value is in String format. + */ + public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54; + + /** + * Video Quality - VideoQualityFeatureValuesConstants. + * Valid values are: {@link #VIDEO_QUALITY_HIGH} and {@link #VIDEO_QUALITY_LOW}. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_VIDEO_QUALITY = 55; + + /** + * Used with {@link #KEY_VIDEO_QUALITY} to indicate low video quality. + */ + public static final int VIDEO_QUALITY_LOW = 0; + + /** + * Used with {@link #KEY_VIDEO_QUALITY} to indicate high video quality. + */ + public static final int VIDEO_QUALITY_HIGH = 1; + + /** + * LTE to WIFI handover threshold. + * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= {@link #KEY_WIFI_THRESHOLD_A}. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_LTE_THRESHOLD_1 = 56; + + /** + * WIFI to LTE handover threshold. + * Handover from WiFi to LTE if LTE >= {@link #KEY_LTE_THRESHOLD_3} or (WiFi < {@link + * #KEY_WIFI_THRESHOLD_B} and LTE >= {@link #KEY_LTE_THRESHOLD_2}). + * Value is in Integer format. + * + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_LTE_THRESHOLD_2 = 57; + + /** + * LTE to WIFI handover threshold. + * Handover from WiFi to LTE if LTE >= {@link #KEY_LTE_THRESHOLD_3} or (WiFi < {@link + * #KEY_WIFI_THRESHOLD_B} and LTE >= {@link #KEY_LTE_THRESHOLD_2}). + * Value is in Integer format. + * + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_LTE_THRESHOLD_3 = 58; + + /** + * 1x to WIFI handover threshold. + * Handover from 1x to WiFi if 1x < {@link #KEY_1X_THRESHOLD}. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_1X_THRESHOLD = 59; + + /** + * LTE to WIFI threshold A. + * Handover from LTE to WiFi if LTE < {@link #KEY_LTE_THRESHOLD_1} and WiFi >= {@link + * #KEY_WIFI_THRESHOLD_A}. + * Value is in Integer format. + * + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_WIFI_THRESHOLD_A = 60; + + /** + * WiFi to LTRE handover threshold B. + * Handover from WiFi to LTE if LTE >= {@link #KEY_LTE_THRESHOLD_3} or (WiFi < + * {@link #KEY_WIFI_THRESHOLD_B} and LTE >= {@link #KEY_LTE_THRESHOLD_2}). + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_WIFI_THRESHOLD_B = 61; + + /** + * LTE ePDG timer (in seconds). + * Device shall not handover back to LTE until the T_ePDG_LTE timer expires. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_LTE_EPDG_TIMER_SEC = 62; + + /** + * WiFi ePDG timer (in seconds). + * Device shall not handover back to WiFi until the T_ePDG_WiFi timer expires. + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_WIFI_EPDG_TIMER_SEC = 63; + + /** + * 1x ePDG timer (in seconds). + * Device shall not re-register on 1x until the T_ePDG_1x timer expires. + */ + public static final int KEY_1X_EPDG_TIMER_SEC = 64; + + /** + * MultiEndpoint status: Enabled (1), or Disabled (0). + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_MULTIENDPOINT_ENABLED = 65; + + /** + * RTT status: Enabled (1), or Disabled (0). + * Value is in Integer format. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + */ + public static final int KEY_RTT_ENABLED = 66; + + /** * Callback for IMS provisioning changes. */ public static class Callback { @@ -225,13 +880,11 @@ public class ProvisioningManager { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull @CallbackExecutor Executor executor, @NonNull Callback callback) throws ImsException { - if (!isImsAvailableOnDevice()) { - throw new ImsException("IMS not available on device.", - ImsException.CODE_ERROR_UNSUPPORTED_OPERATION); - } callback.setExecutor(executor); try { getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder()); + } catch (ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException | IllegalStateException e) { throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } @@ -263,7 +916,7 @@ public class ProvisioningManager { * * @param key An integer that represents the provisioning key, which is defined by the OEM. * @return an integer value for the provided key, or - * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN} if the key doesn't exist. + * {@link #PROVISIONING_RESULT_UNKNOWN} if the key doesn't exist. * @throws IllegalArgumentException if the key provided was invalid. */ @WorkerThread @@ -390,37 +1043,75 @@ public class ProvisioningManager { } /** + * Get the provisioning status for the IMS RCS capability specified. + * + * If provisioning is not required for the queried + * {@link RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag} this method will always return + * {@code true}. + * + * @see CarrierConfigManager#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL + * @return true if the device is provisioned for the capability or does not require + * provisioning, false if the capability does require provisioning and has not been + * provisioned yet. + */ + @WorkerThread + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean getRcsProvisioningStatusForCapability( + @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) { + try { + return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Set the provisioning status for the IMS RCS capability using the specified subscription. + * + * Provisioning may or may not be required, depending on the carrier configuration. If + * provisioning is not required for the carrier associated with this subscription or the device + * does not support the capability/technology combination specified, this operation will be a + * no-op. + * + * @see CarrierConfigManager#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL + * @param isProvisioned true if the device is provisioned for the RCS capability specified, + * false otherwise. + */ + @WorkerThread + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setRcsProvisioningStatusForCapability( + @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, + boolean isProvisioned) { + try { + getITelephony().setRcsProvisioningStatusForCapability(mSubId, capability, + isProvisioned); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** * Notify the framework that an RCS autoconfiguration XML file has been received for * provisioning. + * <p> + * Requires Permission: Manifest.permission.MODIFY_PHONE_STATE or that the calling app has + * carrier privileges (see {@link #hasCarrierPrivileges}). * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed. * @param isCompressed The XML file is compressed in gzip format and must be decompressed * before being read. - * @hide + * */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[] config, boolean isCompressed) { if (config == null) { throw new IllegalArgumentException("Must include a non-null config XML file."); } - // TODO: Connect to ImsConfigImplBase. - throw new UnsupportedOperationException("notifyRcsAutoConfigurationReceived is not" - + "supported"); - } - - private static boolean isImsAvailableOnDevice() { - IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); - if (pm == null) { - // For some reason package manger is not available.. This will fail internally anyways, - // so do not throw error and allow. - return true; - } try { - return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0); + getITelephony().notifyRcsAutoConfigurationReceived(mSubId, config, isCompressed); } catch (RemoteException e) { - // For some reason package manger is not available.. This will fail internally anyways, - // so do not throw error and allow. + throw e.rethrowAsRuntimeException(); } - return true; + } private static ITelephony getITelephony() { diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java index 492170b1069a..3e2903fa6f47 100644 --- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -19,6 +19,7 @@ package android.telephony.ims; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -35,6 +36,7 @@ import java.util.Map; * Contains the User Capability Exchange capabilities corresponding to a contact's URI. * @hide */ +@SystemApi public final class RcsContactUceCapability implements Parcelable { /** Supports 1-to-1 chat */ @@ -81,8 +83,23 @@ public final class RcsContactUceCapability implements Parcelable { public static final int CAPABILITY_RCS_VOICE_CALL = (1 << 19); /** Supports RCS video calling */ public static final int CAPABILITY_RCS_VIDEO_CALL = (1 << 20); - /** Supports RCS video calling, where video media can not be dropped */ + /** Supports RCS video calling, where video media can not be dropped. */ public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = (1 << 21); + /** Supports call composer, where outgoing calls can be enriched with pre-call content.*/ + public static final int CAPABILITY_CALL_COMPOSER = (1 << 22); + /** Supports post call information that is included in the call if the call is missed.*/ + public static final int CAPABILITY_POST_CALL = (1 << 23); + /** Supports sharing a map where the user can draw, share markers, and share their position. */ + public static final int CAPABILITY_SHARED_MAP = (1 << 24); + /** Supports sharing a canvas, where users can draw, add images, and change background colors.*/ + public static final int CAPABILITY_SHARED_SKETCH = (1 << 25); + /** Supports communication with Chatbots. */ + public static final int CAPABILITY_CHAT_BOT = (1 << 26); + /** Supports Chatbot roles. */ + public static final int CAPABILITY_CHAT_BOT_ROLE = (1 << 27); + /** Supports the unidirectional plug-ins framework. */ + public static final int CAPABILITY_PLUG_IN = (1 << 28); + /** @hide*/ @Retention(RetentionPolicy.SOURCE) @@ -108,7 +125,14 @@ public final class RcsContactUceCapability implements Parcelable { CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER, CAPABILITY_RCS_VOICE_CALL, CAPABILITY_RCS_VIDEO_CALL, - CAPABILITY_RCS_VIDEO_ONLY_CALL + CAPABILITY_RCS_VIDEO_ONLY_CALL, + CAPABILITY_CALL_COMPOSER, + CAPABILITY_POST_CALL, + CAPABILITY_SHARED_MAP, + CAPABILITY_SHARED_SKETCH, + CAPABILITY_CHAT_BOT, + CAPABILITY_CHAT_BOT_ROLE, + CAPABILITY_PLUG_IN }) public @interface CapabilityFlag {} @@ -135,7 +159,7 @@ public final class RcsContactUceCapability implements Parcelable { * @param type The capability to map to a service URI that is different from the contact's * URI. */ - public Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) { + public @NonNull Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) { mCapabilities.mCapabilities |= type; // Put each of these capabilities into the map separately. for (int shift = 0; shift < Integer.SIZE; shift++) { @@ -157,7 +181,7 @@ public final class RcsContactUceCapability implements Parcelable { * Add a UCE capability flag that this contact supports. * @param type the capability that the contact supports. */ - public Builder add(@CapabilityFlag int type) { + public @NonNull Builder add(@CapabilityFlag int type) { mCapabilities.mCapabilities |= type; return this; } @@ -167,7 +191,7 @@ public final class RcsContactUceCapability implements Parcelable { * @param extension A string containing a carrier specific service tag that is an extension * of the {@link CapabilityFlag}s that are defined here. */ - public Builder add(@NonNull String extension) { + public @NonNull Builder add(@NonNull String extension) { mCapabilities.mExtensionTags.add(extension); return this; } @@ -175,13 +199,13 @@ public final class RcsContactUceCapability implements Parcelable { /** * @return the constructed instance. */ - public RcsContactUceCapability build() { + public @NonNull RcsContactUceCapability build() { return mCapabilities; } } private final Uri mContactUri; - private int mCapabilities; + private long mCapabilities; private List<String> mExtensionTags = new ArrayList<>(); private Map<Integer, Uri> mServiceMap = new HashMap<>(); @@ -196,7 +220,7 @@ public final class RcsContactUceCapability implements Parcelable { private RcsContactUceCapability(Parcel in) { mContactUri = in.readParcelable(Uri.class.getClassLoader()); - mCapabilities = in.readInt(); + mCapabilities = in.readLong(); in.readStringList(mExtensionTags); // read mServiceMap as key,value pair int mapSize = in.readInt(); @@ -205,7 +229,7 @@ public final class RcsContactUceCapability implements Parcelable { } } - public static final Creator<RcsContactUceCapability> CREATOR = + public static final @NonNull Creator<RcsContactUceCapability> CREATOR = new Creator<RcsContactUceCapability>() { @Override public RcsContactUceCapability createFromParcel(Parcel in) { @@ -219,9 +243,9 @@ public final class RcsContactUceCapability implements Parcelable { }; @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeParcelable(mContactUri, 0); - out.writeInt(mCapabilities); + out.writeLong(mCapabilities); out.writeStringList(mExtensionTags); // write mServiceMap as key,value pairs int mapSize = mServiceMap.keySet().size(); diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index 99bb259602e5..a1f6b78ba7c5 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -22,8 +22,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.TestApi; import android.net.Uri; import android.os.Binder; import android.telephony.AccessNetworkConstants; @@ -41,10 +39,7 @@ import java.util.function.Consumer; /** * Manages IMS Service registration state for associated {@link ImsFeature}s. - * @hide */ -@SystemApi -@TestApi public interface RegistrationManager { /** @@ -139,7 +134,6 @@ public interface RegistrationManager { getAccessType(imsRadioTech), info))); } - @Override public void onSubscriberAssociatedUriChanged(Uri[] uris) { if (mLocalCallback == null) return; @@ -225,7 +219,11 @@ public interface RegistrationManager { /** * Registers a {@link RegistrationCallback} with the system. Use - * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed + * @param executor The {@link Executor} that will be used to call the IMS registration state + * callback. + * @param c A callback called on the supplied {@link Executor} that will contain the + * registration state of the IMS service, which will be one of the + * {@see SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up. * * When the callback is registered, it will initiate the callback c to be called with the @@ -275,10 +273,10 @@ public interface RegistrationManager { * Gets the Transport Type associated with the current IMS registration. * @param executor The {@link Executor} that will be used to call the transportTypeCallback. * @param transportTypeCallback The transport type associated with the current IMS registration, - * which will be one of following: - * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}, - * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or - * {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}. + * which will be one of following: + * {@see AccessNetworkConstants#TRANSPORT_TYPE_WWAN}, + * {@see AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or + * {@see AccessNetworkConstants#TRANSPORT_TYPE_INVALID}. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) void getRegistrationTransportType( diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl index d64e67a40201..cc2ebb9b20bd 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl @@ -92,11 +92,11 @@ oneway interface IImsCallSessionListener { /** * Notifies of handover information for this call */ - void callSessionHandover(int srcAccessTech, int targetAccessTech, + void callSessionHandover(int srcNetworkType, int targetNetworkType, in ImsReasonInfo reasonInfo); - void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech, + void callSessionHandoverFailed(int srcNetworkType, int targetNetworkType, in ImsReasonInfo reasonInfo); - void callSessionMayHandover(int srcAccessTech, int targetAccessTech); + void callSessionMayHandover(int srcNetworkType, int targetNetworkType); /** * Notifies the TTY mode change by remote party. diff --git a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl index 53e459697958..57206c9f059a 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl @@ -40,4 +40,5 @@ interface IImsConfig { // Return result code defined in ImsConfig#OperationStatusConstants int setConfigString(int item, String value); void updateImsCarrierConfigs(in PersistableBundle bundle); + void notifyRcsAutoConfigurationReceived(in byte[] config, boolean isCompressed); } diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl index e81bac0f6764..6f6aa44371fa 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl @@ -19,6 +19,9 @@ package android.telephony.ims.aidl; import android.net.Uri; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IRcsUceControllerCallback; +import android.telephony.ims.aidl.IImsRegistrationCallback; + +import com.android.internal.telephony.IIntegerConsumer; /** * Interface used to interact with the Telephony IMS. @@ -26,6 +29,13 @@ import android.telephony.ims.aidl.IRcsUceControllerCallback; * {@hide} */ interface IImsRcsController { + // IMS RCS registration commands + void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c); + void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c); + void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer); + void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer); + + // IMS RCS capability commands void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback c); void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback c); boolean isCapable(int subId, int capability, int radioTech); diff --git a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl index 881b4776b25b..70cf651d3924 100644 --- a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl @@ -32,11 +32,11 @@ interface IRcsFeatureListener { oneway void onNetworkResponse(int code, in String reason, int operationToken); oneway void onCapabilityRequestResponsePresence(in List<RcsContactUceCapability> infos, int operationToken); - oneway void onNotifyUpdateCapabilities(); + oneway void onNotifyUpdateCapabilities(int publishTriggerType); oneway void onUnpublish(); // RcsSipOptionsImplBase specific oneway void onCapabilityRequestResponseOptions(int code, in String reason, in RcsContactUceCapability info, int operationToken); oneway void onRemoteCapabilityRequest(in Uri contactUri, in RcsContactUceCapability remoteInfo, int operationToken); -}
\ No newline at end of file +} diff --git a/telephony/java/android/telephony/ims/compat/ImsService.java b/telephony/java/android/telephony/ims/compat/ImsService.java index 97a8517afea9..eafbb14539f5 100644 --- a/telephony/java/android/telephony/ims/compat/ImsService.java +++ b/telephony/java/android/telephony/ims/compat/ImsService.java @@ -17,8 +17,8 @@ package android.telephony.ims.compat; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; diff --git a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java index de4f17466a47..5a9e8e2dafc4 100644 --- a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java @@ -17,7 +17,7 @@ package android.telephony.ims.compat.feature; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.IInterface; import android.os.RemoteException; diff --git a/telephony/java/android/telephony/ims/compat/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/compat/feature/MMTelFeature.java index 3fd356a510e6..b52c37106049 100644 --- a/telephony/java/android/telephony/ims/compat/feature/MMTelFeature.java +++ b/telephony/java/android/telephony/ims/compat/feature/MMTelFeature.java @@ -16,8 +16,8 @@ package android.telephony.ims.compat.feature; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Message; import android.os.RemoteException; import android.telephony.ims.ImsCallProfile; diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java index d77f78ea9e88..75bd6a7dc648 100644 --- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java @@ -16,10 +16,11 @@ package android.telephony.ims.compat.stub; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Message; import android.os.RemoteException; import android.telephony.CallQuality; +import android.telephony.ServiceState; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsConferenceState; @@ -547,19 +548,25 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub { @Override public void callSessionHandover(IImsCallSession i, int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo) throws RemoteException { - mNewListener.callSessionHandover(srcAccessTech, targetAccessTech, reasonInfo); + mNewListener.callSessionHandover( + ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech), + ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo); } @Override public void callSessionHandoverFailed(IImsCallSession i, int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo) throws RemoteException { - mNewListener.callSessionHandoverFailed(srcAccessTech, targetAccessTech, reasonInfo); + mNewListener.callSessionHandoverFailed( + ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech), + ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo); } @Override public void callSessionMayHandover(IImsCallSession i, int srcAccessTech, int targetAccessTech) throws RemoteException { - mNewListener.callSessionMayHandover(srcAccessTech, targetAccessTech); + mNewListener.callSessionMayHandover( + ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech), + ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech)); } @Override diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java index e55c3d0823c2..aae6f9214c70 100644 --- a/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java @@ -16,7 +16,7 @@ package android.telephony.ims.compat.stub; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.os.RemoteException; diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java index e2024742c058..ce291d4d14c6 100644 --- a/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java +++ b/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java @@ -16,7 +16,7 @@ package android.telephony.ims.compat.stub; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.RemoteException; import android.telephony.ims.ImsCallForwardInfo; diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 72390d070337..5d102cb4ac06 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -60,15 +60,21 @@ public abstract class ImsFeature { * This feature supports emergency calling over MMTEL. If defined, the framework will try to * place an emergency call over IMS first. If it is not defined, the framework will only use * CSFB for emergency calling. + * @hide */ + @SystemApi @TestApi public static final int FEATURE_EMERGENCY_MMTEL = 0; /** * This feature supports the MMTEL feature. + * @hide */ + @SystemApi @TestApi public static final int FEATURE_MMTEL = 1; /** * This feature supports the RCS feature. + * @hide */ + @SystemApi @TestApi public static final int FEATURE_RCS = 2; /** * Total number of features defined @@ -116,18 +122,24 @@ public abstract class ImsFeature { * This {@link ImsFeature}'s state is unavailable and should not be communicated with. This will * remove all bindings back to the framework. Any attempt to communicate with the framework * during this time will result in an {@link IllegalStateException}. + * @hide */ + @SystemApi @TestApi public static final int STATE_UNAVAILABLE = 0; /** * This {@link ImsFeature} state is initializing and should not be communicated with. This will * remove all bindings back to the framework. Any attempt to communicate with the framework * during this time will result in an {@link IllegalStateException}. + * @hide */ + @SystemApi @TestApi public static final int STATE_INITIALIZING = 1; /** * This {@link ImsFeature} is ready for communication. Do not attempt to call framework methods - * until {@link #onFeatureReady()} is called. + * until {@see #onFeatureReady()} is called. + * @hide */ + @SystemApi @TestApi public static final int STATE_READY = 2; /** @@ -155,11 +167,15 @@ public abstract class ImsFeature { /** * The capability was unable to be changed. + * @hide */ + @SystemApi @TestApi public static final int CAPABILITY_ERROR_GENERIC = -1; /** * The capability was able to be changed. + * @hide */ + @SystemApi @TestApi public static final int CAPABILITY_SUCCESS = 0; /** @@ -331,17 +347,20 @@ public abstract class ImsFeature { * * @see SubscriptionManager#getSubscriptionIds(int) for more information on getting the * subscription IDs associated with this slot. + * @hide */ + @SystemApi @TestApi public final int getSlotIndex() { return mSlotId; } /** - * @return The current state of the feature, defined as {@link #STATE_UNAVAILABLE}, - * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}. + * @return The current state of the ImsFeature, set previously by {@link #setFeatureState(int)} + * or {@link #STATE_UNAVAILABLE} if it has not been updated yet. * @hide */ - public int getFeatureState() { + @SystemApi @TestApi + public @ImsState int getFeatureState() { synchronized (mLock) { return mState; } @@ -352,7 +371,9 @@ public abstract class ImsFeature { * stop communication, depending on the state sent. * @param state The ImsFeature's state, defined as {@link #STATE_UNAVAILABLE}, * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}. + * @hide */ + @SystemApi @TestApi public final void setFeatureState(@ImsState int state) { synchronized (mLock) { if (mState != state) { diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index 56c87710244c..0d5a979e5894 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -52,14 +52,18 @@ import java.lang.annotation.RetentionPolicy; * * Any class wishing to use MmTelFeature should extend this class and implement all methods that the * service supports. - * @hide */ -@SystemApi -@TestApi public class MmTelFeature extends ImsFeature { private static final String LOG_TAG = "MmTelFeature"; + /** + * @hide + */ + @SystemApi @TestApi + public MmTelFeature() { + } + private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() { @Override @@ -215,11 +219,11 @@ public class MmTelFeature extends ImsFeature { * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}. * * The capabilities of this MmTelFeature will be set by the framework and can be queried with - * {@link #queryCapabilityStatus()}. + * {@see #queryCapabilityStatus()}. * * This MmTelFeature can then return the status of each of these capabilities (enabled or not) - * by sending a {@link #notifyCapabilitiesStatusChanged} callback to the framework. The current - * status can also be queried using {@link #queryCapabilityStatus()}. + * by sending a {@see #notifyCapabilitiesStatusChanged} callback to the framework. The current + * status can also be queried using {@see #queryCapabilityStatus()}. * @see #isCapable(int) */ public static class MmTelCapabilities extends Capabilities { @@ -228,13 +232,18 @@ public class MmTelFeature extends ImsFeature { * Create a new empty {@link MmTelCapabilities} instance. * @see #addCapabilities(int) * @see #removeCapabilities(int) + * @hide */ + @SystemApi @TestApi public MmTelCapabilities() { super(); } - /**@deprecated Use {@link MmTelCapabilities} to construct a new instance instead.*/ + /**@deprecated Use {@link MmTelCapabilities} to construct a new instance instead. + * @hide + */ @Deprecated + @SystemApi @TestApi public MmTelCapabilities(Capabilities c) { mCapabilities = c.mCapabilities; } @@ -243,11 +252,17 @@ public class MmTelFeature extends ImsFeature { * Create a new {link @MmTelCapabilities} instance with the provided capabilities. * @param capabilities The capabilities that are supported for MmTel in the form of a * bitfield. + * @hide */ + @SystemApi @TestApi public MmTelCapabilities(@MmTelCapability int capabilities) { super(capabilities); } + /** + * @hide + */ + @SystemApi @TestApi @IntDef(flag = true, value = { CAPABILITY_TYPE_VOICE, @@ -278,23 +293,39 @@ public class MmTelFeature extends ImsFeature { */ public static final int CAPABILITY_TYPE_SMS = 1 << 3; + /** + * @hide + */ @Override + @SystemApi @TestApi public final void addCapabilities(@MmTelCapability int capabilities) { super.addCapabilities(capabilities); } + /** + * @hide + */ @Override + @SystemApi @TestApi public final void removeCapabilities(@MmTelCapability int capability) { super.removeCapabilities(capability); } + /** + * @hide + */ @Override + @SystemApi @TestApi public final boolean isCapable(@MmTelCapability int capabilities) { return super.isCapable(capabilities); } + /** + * @hide + */ @NonNull @Override + @SystemApi @TestApi public String toString() { StringBuilder builder = new StringBuilder("MmTel Capabilities - ["); builder.append("Voice: "); @@ -319,8 +350,10 @@ public class MmTelFeature extends ImsFeature { /** * Called when the IMS provider receives an incoming call. * @param c The {@link ImsCallSession} associated with the new call. + * @hide */ @Override + @SystemApi @TestApi public void onIncomingCall(IImsCallSession c, Bundle extras) { } @@ -329,8 +362,10 @@ public class MmTelFeature extends ImsFeature { * Called when the IMS provider implicitly rejects an incoming call during setup. * @param callProfile An {@link ImsCallProfile} with the call details. * @param reason The {@link ImsReasonInfo} reason for call rejection. + * @hide */ @Override + @SystemApi @TestApi public void onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) { } @@ -338,8 +373,10 @@ public class MmTelFeature extends ImsFeature { /** * Updates the Listener when the voice message count for IMS has changed. * @param count an integer representing the new message count. + * @hide */ @Override + @SystemApi @TestApi public void onVoiceMessageCountUpdate(int count) { } @@ -348,14 +385,22 @@ public class MmTelFeature extends ImsFeature { /** * To be returned by {@link #shouldProcessCall(String[])} when the ImsService should process the * outgoing call as IMS. + * @hide */ + @SystemApi @TestApi public static final int PROCESS_CALL_IMS = 0; /** * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should * not process the outgoing call as IMS and should instead use circuit switch. + * @hide */ + @SystemApi @TestApi public static final int PROCESS_CALL_CSFB = 1; + /** + * @hide + */ + @SystemApi @TestApi @IntDef(flag = true, value = { PROCESS_CALL_IMS, @@ -368,7 +413,9 @@ public class MmTelFeature extends ImsFeature { * If the flag is present and true, it indicates that the incoming call is for USSD. * <p> * This is an optional boolean flag. + * @hide */ + @SystemApi @TestApi public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD"; /** @@ -379,7 +426,9 @@ public class MmTelFeature extends ImsFeature { * certain situations. * <p> * This is an optional boolean flag. + * @hide */ + @SystemApi @TestApi public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; @@ -388,6 +437,7 @@ 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) { @@ -406,9 +456,11 @@ public class MmTelFeature extends ImsFeature { * Should be a subset of the capabilities that are enabled by the framework in * {@link #changeEnabledCapabilities}. * @return A copy of the current MmTelFeature capability status. + * @hide */ @Override - public final MmTelCapabilities queryCapabilityStatus() { + @SystemApi @TestApi + public @NonNull final MmTelCapabilities queryCapabilityStatus() { return new MmTelCapabilities(super.queryCapabilityStatus()); } @@ -420,7 +472,9 @@ public class MmTelFeature extends ImsFeature { * the status of that capability is disabled. This can happen if the network does not currently * support the capability that is enabled. A capability that is disabled by the framework (via * {@link #changeEnabledCapabilities}) should also show the status as disabled. + * @hide */ + @SystemApi @TestApi public final void notifyCapabilitiesStatusChanged(@NonNull MmTelCapabilities c) { if (c == null) { throw new IllegalArgumentException("MmTelCapabilities must be non-null!"); @@ -433,7 +487,9 @@ public class MmTelFeature extends ImsFeature { * @param c The {@link ImsCallSessionImplBase} of the new incoming call. * @param extras A bundle containing extra parameters related to the call. See * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above. + * @hide */ + @SystemApi @TestApi public final void notifyIncomingCall(@NonNull ImsCallSessionImplBase c, @NonNull Bundle extras) { if (c == null || extras == null) { @@ -458,7 +514,9 @@ public class MmTelFeature extends ImsFeature { * @param callProfile The {@link ImsCallProfile} IMS call profile with details. * This can be null if no call information is available for the rejected call. * @param reason The {@link ImsReasonInfo} call rejection reason. + * * @hide */ + @SystemApi @TestApi public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile, @NonNull ImsReasonInfo reason) { if (callProfile == null || reason == null) { @@ -497,7 +555,9 @@ public class MmTelFeature extends ImsFeature { /** * Notify the framework of a change in the Voice Message count. * @link count the new Voice Message count. + * @hide */ + @SystemApi @TestApi public final void notifyVoiceMessageCountUpdate(int count) { synchronized (mLock) { if (mListener == null) { @@ -518,8 +578,10 @@ public class MmTelFeature extends ImsFeature { * status for capability A. * @param capability The capability that we are querying the configuration for. * @return true if the capability is enabled, false otherwise. + * @hide */ @Override + @SystemApi @TestApi public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { // Base implementation - Override to provide functionality @@ -537,8 +599,10 @@ public class MmTelFeature extends ImsFeature { * Enabling/Disabling a capability here indicates that the capability should be registered or * deregistered (depending on the capability change) and become available or unavailable to * the framework. + * * @hide */ @Override + @SystemApi @TestApi public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request, @NonNull CapabilityCallbackProxy c) { // Base implementation, no-op @@ -561,7 +625,9 @@ public class MmTelFeature extends ImsFeature { * {@link ImsCallProfile#CALL_TYPE_VS_TX} * {@link ImsCallProfile#CALL_TYPE_VS_RX} * @return a {@link ImsCallProfile} object + * @hide */ + @SystemApi @TestApi public @Nullable ImsCallProfile createCallProfile(int callSessionType, int callType) { // Base Implementation - Should be overridden return null; @@ -582,7 +648,9 @@ public class MmTelFeature extends ImsFeature { * {@link ImsCallSession} directly. * * @param profile a call profile to make the call + * @hide */ + @SystemApi @TestApi public @Nullable ImsCallSessionImplBase createCallSession(@NonNull ImsCallProfile profile) { // Base Implementation - Should be overridden return null; @@ -599,7 +667,9 @@ public class MmTelFeature extends ImsFeature { * call as a conference. * @return a {@link ProcessCallResult} to the framework, which will be used to determine if the * call will be placed over IMS or via CSFB. + * @hide */ + @SystemApi @TestApi public @ProcessCallResult int shouldProcessCall(@NonNull String[] numbers) { return PROCESS_CALL_IMS; } @@ -632,7 +702,9 @@ public class MmTelFeature extends ImsFeature { /** * @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service * configuration. + * @hide */ + @SystemApi @TestApi public @NonNull ImsUtImplBase getUt() { // Base Implementation - Should be overridden return new ImsUtImplBase(); @@ -641,7 +713,9 @@ public class MmTelFeature extends ImsFeature { /** * @return The {@link ImsEcbmImplBase} Emergency call-back mode interface for emergency VoLTE * calls that support it. + * @hide */ + @SystemApi @TestApi public @NonNull ImsEcbmImplBase getEcbm() { // Base Implementation - Should be overridden return new ImsEcbmImplBase(); @@ -650,7 +724,9 @@ public class MmTelFeature extends ImsFeature { /** * @return The {@link ImsMultiEndpointImplBase} implementation for implementing Dialog event * package processing for multi-endpoint. + * @hide */ + @SystemApi @TestApi public @NonNull ImsMultiEndpointImplBase getMultiEndpoint() { // Base Implementation - Should be overridden return new ImsMultiEndpointImplBase(); @@ -676,7 +752,9 @@ public class MmTelFeature extends ImsFeature { * // Remote side is dead * } * } + * @hide */ + @SystemApi @TestApi public void setUiTtyMode(int mode, @Nullable Message onCompleteMessage) { // Base Implementation - Should be overridden } @@ -710,7 +788,9 @@ public class MmTelFeature extends ImsFeature { * * @return an instance of {@link ImsSmsImplBase} which should be implemented by the IMS * Provider. + * @hide */ + @SystemApi @TestApi public @NonNull ImsSmsImplBase getSmsImplementation() { return new ImsSmsImplBase(); } @@ -719,14 +799,22 @@ public class MmTelFeature extends ImsFeature { return getSmsImplementation().getSmsFormat(); } - /**{@inheritDoc}*/ + /** + * {@inheritDoc} + * @hide + */ @Override + @SystemApi @TestApi public void onFeatureRemoved() { // Base Implementation - Should be overridden } - /**{@inheritDoc}*/ + /** + * {@inheritDoc} + * @hide + */ @Override + @SystemApi @TestApi public void onFeatureReady() { // Base Implementation - Should be overridden } diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index 4c0de7f9c1b7..e0d576db4f14 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -17,12 +17,14 @@ package android.telephony.ims.stub; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; import android.os.PersistableBundle; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.telephony.ims.ProvisioningManager; import android.telephony.ims.aidl.IImsConfig; import android.telephony.ims.aidl.IImsConfigCallback; import android.util.Log; @@ -199,6 +201,12 @@ public class ImsConfigImplBase { } } + @Override + public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) + throws RemoteException { + getImsConfigImpl().notifyRcsAutoConfigurationReceived(config, isCompressed); + } + private void notifyImsConfigChanged(int item, int value) throws RemoteException { getImsConfigImpl().notifyConfigChanged(item, value); } @@ -228,7 +236,8 @@ public class ImsConfigImplBase { * The configuration requested resulted in an unknown result. This may happen if the * IMS configurations are unavailable. */ - public static final int CONFIG_RESULT_UNKNOWN = -1; + public static final int CONFIG_RESULT_UNKNOWN = ProvisioningManager.PROVISIONING_RESULT_UNKNOWN; + /** * Setting the configuration value completed. */ @@ -355,9 +364,9 @@ public class ImsConfigImplBase { * @param config The XML file to be read, if not compressed, it should be in ASCII/UTF8 format. * @param isCompressed The XML file is compressed in gzip format and must be decompressed * before being read. - * @hide + * */ - public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) { + public void notifyRcsAutoConfigurationReceived(@NonNull byte[] config, boolean isCompressed) { } /** diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java index feac3c2ebfde..3ec4f3468497 100644 --- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java @@ -16,6 +16,7 @@ package android.telephony.ims.stub; +import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Bundle; @@ -25,6 +26,9 @@ import android.telephony.ims.ImsUtListener; import com.android.ims.internal.IImsUt; import com.android.ims.internal.IImsUtListener; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Base implementation of IMS UT interface, which implements stubs. Override these methods to * implement functionality. @@ -36,6 +40,70 @@ import com.android.ims.internal.IImsUtListener; @SystemApi @TestApi public class ImsUtImplBase { + /** + * Bar all incoming calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_ALL_INCOMING = 1; + + /** + * Bar all outgoing calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_ALL_OUTGOING = 2; + + /** + * Bar all outgoing international calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_OUTGOING_INTL = 3; + + /** + * Bar all outgoing international calls, excluding those to the home PLMN country + * (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; + + /** + * Bar all incoming calls when roaming (See 3GPP TS 24.611) + */ + public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; + + /** + * Enable Anonymous Communication Rejection (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; + + /** + * Bar all incoming and outgoing calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_ALL = 7; + + /** + * Bar all outgoing service requests, including calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; + + /** + * Bar all incoming service requests, including calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; + + /** + * Bar specific incoming calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "CALL_BARRING_", value = {CALL_BARRING_ALL_INCOMING, CALL_BARRING_ALL_OUTGOING, + CALL_BARRING_OUTGOING_INTL, CALL_BARRING_OUTGOING_INTL_EXCL_HOME, + CALL_BLOCKING_INCOMING_WHEN_ROAMING, CALL_BARRING_ANONYMOUS_INCOMING, + CALL_BARRING_ALL, CALL_BARRING_OUTGOING_ALL_SERVICES, + CALL_BARRING_INCOMING_ALL_SERVICES, CALL_BARRING_SPECIFIC_INCOMING_CALLS}) + public @interface CallBarringMode {} + + /** + * Constant used to denote an invalid return value. + */ + public static final int INVALID_RESULT = -1; private IImsUt.Stub mServiceImpl = new IImsUt.Stub() { @Override @@ -247,15 +315,15 @@ public class ImsUtImplBase { /** * Updates the configuration of the call barring. */ - public int updateCallBarring(int cbType, int action, String[] barrList) { + public int updateCallBarring(@CallBarringMode int cbType, int action, String[] barrList) { return -1; } /** * Updates the configuration of the call barring for specified service class. */ - public int updateCallBarringForServiceClass(int cbType, int action, String[] barrList, - int serviceClass) { + public int updateCallBarringForServiceClass(@CallBarringMode int cbType, int action, + String[] barrList, int serviceClass) { return -1; } diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java index 055fca57a628..bb034489a296 100644 --- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java @@ -113,6 +113,51 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { }) public @interface PresenceResponseCode {} + + /** A capability update has been requested due to the Entity Tag (ETag) expiring. */ + public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; + /** A capability update has been requested due to moving to LTE with VoPS disabled. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; + /** A capability update has been requested due to moving to LTE with VoPS enabled. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; + /** A capability update has been requested due to moving to eHRPD. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; + /** A capability update has been requested due to moving to HSPA+. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; + /** A capability update has been requested due to moving to 3G. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; + /** A capability update has been requested due to moving to 2G. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; + /** A capability update has been requested due to moving to WLAN */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; + /** A capability update has been requested due to moving to IWLAN */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; + /** A capability update has been requested but the reason is unknown. */ + public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; + /** A capability update has been requested due to moving to 5G NR with VoPS disabled. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; + /** A capability update has been requested due to moving to 5G NR with VoPS enabled. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; + + /** @hide*/ + @IntDef(value = { + CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN, + CAPABILITY_UPDATE_TRIGGER_UNKNOWN, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED + }, prefix = "CAPABILITY_UPDATE_TRIGGER_") + @Retention(RetentionPolicy.SOURCE) + public @interface StackPublishTriggerType { + } + /** * Provide the framework with a subsequent network response update to * {@link #updateCapabilities(RcsContactUceCapability, int)} and @@ -164,15 +209,18 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { * This is typically used when trying to generate an initial PUBLISH for a new subscription to * the network. The device will cache all presence publications after boot until this method is * called once. + * @param publishTriggerType {@link StackPublishTriggerType} The reason for the capability + * update request. * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently * connected to the framework. This can happen if the {@link RcsFeature} is not * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the * Telephony stack has crashed. */ - public final void onNotifyUpdateCapabilites() throws ImsException { + public final void onNotifyUpdateCapabilites(@StackPublishTriggerType int publishTriggerType) + throws ImsException { try { - getListener().onNotifyUpdateCapabilities(); + getListener().onNotifyUpdateCapabilities(publishTriggerType); } catch (RemoteException e) { throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java index 4fc6a19d1f38..0f6ce13a6ce4 100644 --- a/telephony/java/com/android/ims/ImsConfig.java +++ b/telephony/java/com/android/ims/ImsConfig.java @@ -17,15 +17,16 @@ package com.android.ims; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.os.RemoteException; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.aidl.IImsConfig; import android.telephony.ims.aidl.IImsConfigCallback; +import com.android.internal.telephony.util.HandlerExecutor; + import java.util.concurrent.Executor; /** @@ -134,363 +135,596 @@ public class ImsConfig { /** * AMR CODEC Mode Value set, 0-7 in comma separated sequence. * Value is in String format. + * @deprecated use {@link ProvisioningManager#KEY_AMR_CODEC_MODE_SET_VALUES} instead. */ - public static final int VOCODER_AMRMODESET = CONFIG_START; + @Deprecated + public static final int VOCODER_AMRMODESET = + ProvisioningManager.KEY_AMR_CODEC_MODE_SET_VALUES; /** * Wide Band AMR CODEC Mode Value set,0-7 in comma separated sequence. * Value is in String format. + * @deprecated use {@link ProvisioningManager#KEY_AMR_WB_CODEC_MODE_SET_VALUES} instead. */ - public static final int VOCODER_AMRWBMODESET = 1; + @Deprecated + public static final int VOCODER_AMRWBMODESET = + ProvisioningManager.KEY_AMR_WB_CODEC_MODE_SET_VALUES; /** * SIP Session Timer value (seconds). * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_SIP_SESSION_TIMER_SEC} instead. */ - public static final int SIP_SESSION_TIMER = 2; + @Deprecated + public static final int SIP_SESSION_TIMER = ProvisioningManager.KEY_SIP_SESSION_TIMER_SEC; /** * Minimum SIP Session Expiration Timer in (seconds). * Value is in Integer format. + * @deprecated use + * {@link ProvisioningManager#KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC} instead. */ - public static final int MIN_SE = 3; + @Deprecated + public static final int MIN_SE = + ProvisioningManager.KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC; /** * SIP_INVITE cancellation time out value (in milliseconds). Integer format. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_SIP_INVITE_CANCELLATION_TIMER_MS} instead. */ - public static final int CANCELLATION_TIMER = 4; + @Deprecated + public static final int CANCELLATION_TIMER = + ProvisioningManager.KEY_SIP_INVITE_CANCELLATION_TIMER_MS; /** * Delay time when an iRAT transition from eHRPD/HRPD/1xRTT to LTE. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_TRANSITION_TO_LTE_DELAY_MS} instead. */ - public static final int TDELAY = 5; + @Deprecated + public static final int TDELAY = ProvisioningManager.KEY_TRANSITION_TO_LTE_DELAY_MS; /** * Silent redial status of Enabled (True), or Disabled (False). * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_ENABLE_SILENT_REDIAL} instead. */ - public static final int SILENT_REDIAL_ENABLE = 6; + @Deprecated + public static final int SILENT_REDIAL_ENABLE = ProvisioningManager.KEY_ENABLE_SILENT_REDIAL; /** * SIP T1 timer value in milliseconds. See RFC 3261 for define. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_T1_TIMER_VALUE_MS} instead. */ - public static final int SIP_T1_TIMER = 7; + @Deprecated + public static final int SIP_T1_TIMER = ProvisioningManager.KEY_T1_TIMER_VALUE_MS; /** * SIP T2 timer value in milliseconds. See RFC 3261 for define. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_T2_TIMER_VALUE_MS} instead. */ - public static final int SIP_T2_TIMER = 8; + @Deprecated + public static final int SIP_T2_TIMER = ProvisioningManager.KEY_T2_TIMER_VALUE_MS; - /** + /** * SIP TF timer value in milliseconds. See RFC 3261 for define. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_TF_TIMER_VALUE_MS} instead. */ - public static final int SIP_TF_TIMER = 9; + @Deprecated + public static final int SIP_TF_TIMER = ProvisioningManager.KEY_TF_TIMER_VALUE_MS; /** * VoLTE status for VLT/s status of Enabled (1), or Disabled (0). * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS} instead. */ - public static final int VLT_SETTING_ENABLED = 10; + @Deprecated + public static final int VLT_SETTING_ENABLED = + ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS; /** * VoLTE status for LVC/s status of Enabled (1), or Disabled (0). * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS} instead. */ - public static final int LVC_SETTING_ENABLED = 11; + @Deprecated + public static final int LVC_SETTING_ENABLED = + ProvisioningManager.KEY_VT_PROVISIONING_STATUS; + /** * Domain Name for the device to populate the request URI for REGISTRATION. * Value is in String format. + * @deprecated use {@link ProvisioningManager#KEY_REGISTRATION_DOMAIN_NAME}. */ - public static final int DOMAIN_NAME = 12; + @Deprecated + public static final int DOMAIN_NAME = ProvisioningManager.KEY_REGISTRATION_DOMAIN_NAME; + /** * Device Outgoing SMS based on either 3GPP or 3GPP2 standards. * Value is in Integer format. 3GPP2(0), 3GPP(1) - */ - public static final int SMS_FORMAT = 13; + * @deprecated use {@link ProvisioningManager#KEY_SMS_FORMAT}. + */ + @Deprecated + public static final int SMS_FORMAT = ProvisioningManager.KEY_SMS_FORMAT; + /** * Turns IMS ON/OFF on the device. * Value is in Integer format. ON (1), OFF(0). - */ - public static final int SMS_OVER_IP = 14; + * @deprecated use {@link ProvisioningManager#KEY_SMS_OVER_IP_ENABLED}. + */ + @Deprecated + public static final int SMS_OVER_IP = ProvisioningManager.KEY_SMS_OVER_IP_ENABLED; + /** * Requested expiration for Published Online availability. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_PUBLISH_TIMER_SEC}. */ - public static final int PUBLISH_TIMER = 15; + @Deprecated + public static final int PUBLISH_TIMER = ProvisioningManager.KEY_RCS_PUBLISH_TIMER_SEC; + /** * Requested expiration for Published Offline availability. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC}. */ - public static final int PUBLISH_TIMER_EXTENDED = 16; + @Deprecated + public static final int PUBLISH_TIMER_EXTENDED = + ProvisioningManager.KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC; + /** * * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_CAPABILITY_DISCOVERY_ENABLED}. */ - public static final int CAPABILITY_DISCOVERY_ENABLED = 17; + @Deprecated + public static final int CAPABILITY_DISCOVERY_ENABLED = + ProvisioningManager.KEY_RCS_CAPABILITY_DISCOVERY_ENABLED; + /** - * Period of time the capability information of the contact is cached on handset. + * Period of time the capability information of the contact is cached on handset. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC}. */ - public static final int CAPABILITIES_CACHE_EXPIRATION = 18; + @Deprecated + public static final int CAPABILITIES_CACHE_EXPIRATION = + ProvisioningManager.KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC; + /** * Peiod of time the availability information of a contact is cached on device. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC}. */ - public static final int AVAILABILITY_CACHE_EXPIRATION = 19; + @Deprecated + public static final int AVAILABILITY_CACHE_EXPIRATION = + ProvisioningManager.KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC; + /** * Interval between successive capabilities polling. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC}. */ - public static final int CAPABILITIES_POLL_INTERVAL = 20; + @Deprecated + public static final int CAPABILITIES_POLL_INTERVAL = + ProvisioningManager.KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC; + /** * Minimum time between two published messages from the device. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS}. */ - public static final int SOURCE_THROTTLE_PUBLISH = 21; + @Deprecated + public static final int SOURCE_THROTTLE_PUBLISH = + ProvisioningManager.KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS; + /** * The Maximum number of MDNs contained in one Request Contained List. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_MAX_NUM_ENTRIES_IN_RCL}. */ - public static final int MAX_NUMENTRIES_IN_RCL = 22; + @Deprecated + public static final int MAX_NUMENTRIES_IN_RCL = + ProvisioningManager.KEY_RCS_MAX_NUM_ENTRIES_IN_RCL; + /** * Expiration timer for subscription of a Request Contained List, used in capability * polling. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC}. */ - public static final int CAPAB_POLL_LIST_SUB_EXP = 23; + @Deprecated + public static final int CAPAB_POLL_LIST_SUB_EXP = + ProvisioningManager.KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC; + /** * Applies compression to LIST Subscription. * Value is in Integer format. Enable (1), Disable(0). + * @deprecated use {@link ProvisioningManager#KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION}. */ - public static final int GZIP_FLAG = 24; + @Deprecated + public static final int GZIP_FLAG = ProvisioningManager.KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION; + /** * VOLTE Status for EAB/s status of Enabled (1), or Disabled (0). * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}. */ - public static final int EAB_SETTING_ENABLED = 25; + @Deprecated + public static final int EAB_SETTING_ENABLED = + ProvisioningManager.KEY_EAB_PROVISIONING_STATUS; + /** * Wi-Fi calling roaming status. * Value is in Integer format. ON (1), OFF(0). + * @deprecated use {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE} + * instead. */ + @Deprecated public static final int VOICE_OVER_WIFI_ROAMING = ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE; + /** - * Wi-Fi calling modem - WfcModeFeatureValueConstants. + * Wi-Fi calling mode - WfcModeFeatureValueConstants. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_MODE_OVERRIDE} + * instead. */ + @Deprecated public static final int VOICE_OVER_WIFI_MODE = ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE; + /** * VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0). * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}. */ - public static final int VOICE_OVER_WIFI_SETTING_ENABLED = 28; + @Deprecated + public static final int VOICE_OVER_WIFI_SETTING_ENABLED = + ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE; + + /** * Mobile data enabled. * Value is in Integer format. On (1), OFF(0). + * @deprecated use {@link ProvisioningManager#KEY_MOBILE_DATA_ENABLED}. */ - public static final int MOBILE_DATA_ENABLED = 29; + @Deprecated + public static final int MOBILE_DATA_ENABLED = ProvisioningManager.KEY_MOBILE_DATA_ENABLED; + /** * VoLTE user opted in status. * Value is in Integer format. Opted-in (1) Opted-out (0). + * @deprecated use {@link ProvisioningManager#KEY_VOLTE_USER_OPT_IN_STATUS}. */ - public static final int VOLTE_USER_OPT_IN_STATUS = 30; + @Deprecated + public static final int VOLTE_USER_OPT_IN_STATUS = + ProvisioningManager.KEY_VOLTE_USER_OPT_IN_STATUS; + /** * Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO). * Value is in String format. + * @deprecated use {@link ProvisioningManager#KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS}. */ - public static final int LBO_PCSCF_ADDRESS = 31; + @Deprecated + public static final int LBO_PCSCF_ADDRESS = + ProvisioningManager.KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS; + /** * Keep Alive Enabled for SIP. * Value is in Integer format. On(1), OFF(0). + * @deprecated use {@link ProvisioningManager#KEY_SIP_KEEP_ALIVE_ENABLED}. */ - public static final int KEEP_ALIVE_ENABLED = 32; + @Deprecated + public static final int KEEP_ALIVE_ENABLED = ProvisioningManager.KEY_SIP_KEEP_ALIVE_ENABLED; + /** * Registration retry Base Time value in seconds. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_REGISTRATION_RETRY_BASE_TIME_SEC}. */ - public static final int REGISTRATION_RETRY_BASE_TIME_SEC = 33; + @Deprecated + public static final int REGISTRATION_RETRY_BASE_TIME_SEC = + ProvisioningManager.KEY_REGISTRATION_RETRY_BASE_TIME_SEC; + /** * Registration retry Max Time value in seconds. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_REGISTRATION_RETRY_MAX_TIME_SEC}. */ - public static final int REGISTRATION_RETRY_MAX_TIME_SEC = 34; + @Deprecated + public static final int REGISTRATION_RETRY_MAX_TIME_SEC = + ProvisioningManager.KEY_REGISTRATION_RETRY_MAX_TIME_SEC; + /** * Smallest RTP port for speech codec. * Value is in integer format. + * @deprecated use {@link ProvisioningManager#KEY_RTP_SPEECH_START_PORT}. */ - public static final int SPEECH_START_PORT = 35; + @Deprecated + public static final int SPEECH_START_PORT = ProvisioningManager.KEY_RTP_SPEECH_START_PORT; + /** * Largest RTP port for speech code. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RTP_SPEECH_END_PORT}. */ - public static final int SPEECH_END_PORT = 36; + @Deprecated + public static final int SPEECH_END_PORT = ProvisioningManager.KEY_RTP_SPEECH_END_PORT; + /** * SIP Timer A's value in milliseconds. Timer A is the INVITE request * retransmit interval, for UDP only. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS}. */ - public static final int SIP_INVITE_REQ_RETX_INTERVAL_MSEC = 37; + @Deprecated + public static final int SIP_INVITE_REQ_RETX_INTERVAL_MSEC = + ProvisioningManager.KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS; + /** * SIP Timer B's value in milliseconds. Timer B is the wait time for * INVITE message to be acknowledged. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_SIP_INVITE_ACK_WAIT_TIME_MS}. */ - public static final int SIP_INVITE_RSP_WAIT_TIME_MSEC = 38; + @Deprecated + public static final int SIP_INVITE_RSP_WAIT_TIME_MSEC = + ProvisioningManager.KEY_SIP_INVITE_ACK_WAIT_TIME_MS; + /** * SIP Timer D's value in milliseconds. Timer D is the wait time for * response retransmits of the invite client transactions. * Value is in Integer format. + * @deprecated use + * {@link ProvisioningManager#KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS}. */ - public static final int SIP_INVITE_RSP_RETX_WAIT_TIME_MSEC = 39; + @Deprecated + public static final int SIP_INVITE_RSP_RETX_WAIT_TIME_MSEC = + ProvisioningManager.KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS; + /** * SIP Timer E's value in milliseconds. Timer E is the value Non-INVITE * request retransmit interval, for UDP only. * Value is in Integer format. + * @deprecated use + * {@link ProvisioningManager#KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS}. */ - public static final int SIP_NON_INVITE_REQ_RETX_INTERVAL_MSEC = 40; + @Deprecated + public static final int SIP_NON_INVITE_REQ_RETX_INTERVAL_MSEC = + ProvisioningManager.KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS; + /** * SIP Timer F's value in milliseconds. Timer F is the Non-INVITE transaction * timeout timer. * Value is in Integer format. + * @deprecated use + * {@link ProvisioningManager#KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS}. */ - public static final int SIP_NON_INVITE_TXN_TIMEOUT_TIMER_MSEC = 41; + @Deprecated + public static final int SIP_NON_INVITE_TXN_TIMEOUT_TIMER_MSEC = + ProvisioningManager.KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS; + /** * SIP Timer G's value in milliseconds. Timer G is the value of INVITE response * retransmit interval. * Value is in Integer format. + * @deprecated use + * {@link ProvisioningManager#KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS}. */ - public static final int SIP_INVITE_RSP_RETX_INTERVAL_MSEC = 42; + @Deprecated + public static final int SIP_INVITE_RSP_RETX_INTERVAL_MSEC = + ProvisioningManager.KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS; + /** * SIP Timer H's value in milliseconds. Timer H is the value of wait time for * ACK receipt. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS}. */ - public static final int SIP_ACK_RECEIPT_WAIT_TIME_MSEC = 43; + @Deprecated + public static final int SIP_ACK_RECEIPT_WAIT_TIME_MSEC = + ProvisioningManager.KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS; + /** * SIP Timer I's value in milliseconds. Timer I is the value of wait time for * ACK retransmits. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS}. */ - public static final int SIP_ACK_RETX_WAIT_TIME_MSEC = 44; + @Deprecated + public static final int SIP_ACK_RETX_WAIT_TIME_MSEC = + ProvisioningManager.KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS; + /** * SIP Timer J's value in milliseconds. Timer J is the value of wait time for * non-invite request retransmission. * Value is in Integer format. + * @deprecated use + * {@link ProvisioningManager#KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS}. */ - public static final int SIP_NON_INVITE_REQ_RETX_WAIT_TIME_MSEC = 45; + @Deprecated + public static final int SIP_NON_INVITE_REQ_RETX_WAIT_TIME_MSEC = + ProvisioningManager.KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS; + /** * SIP Timer K's value in milliseconds. Timer K is the value of wait time for * non-invite response retransmits. * Value is in Integer format. + * @deprecated use + * {@link ProvisioningManager#KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS}. */ - public static final int SIP_NON_INVITE_RSP_RETX_WAIT_TIME_MSEC = 46; + @Deprecated + public static final int SIP_NON_INVITE_RSP_RETX_WAIT_TIME_MSEC = + ProvisioningManager.KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS; + /** * AMR WB octet aligned dynamic payload type. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE}. */ - public static final int AMR_WB_OCTET_ALIGNED_PT = 47; + @Deprecated + public static final int AMR_WB_OCTET_ALIGNED_PT = + ProvisioningManager.KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE; + /** * AMR WB bandwidth efficient payload type. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE}. */ - public static final int AMR_WB_BANDWIDTH_EFFICIENT_PT = 48; + @Deprecated + public static final int AMR_WB_BANDWIDTH_EFFICIENT_PT = + ProvisioningManager.KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE; + /** * AMR octet aligned dynamic payload type. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE}. */ - public static final int AMR_OCTET_ALIGNED_PT = 49; + @Deprecated + public static final int AMR_OCTET_ALIGNED_PT = + ProvisioningManager.KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE; + /** * AMR bandwidth efficient payload type. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE}. */ - public static final int AMR_BANDWIDTH_EFFICIENT_PT = 50; + @Deprecated + public static final int AMR_BANDWIDTH_EFFICIENT_PT = + ProvisioningManager.KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE; + /** * DTMF WB payload type. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_DTMF_WB_PAYLOAD_TYPE}. */ - public static final int DTMF_WB_PT = 51; + @Deprecated + public static final int DTMF_WB_PT = ProvisioningManager.KEY_DTMF_WB_PAYLOAD_TYPE; + /** * DTMF NB payload type. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_DTMF_NB_PAYLOAD_TYPE}. */ - public static final int DTMF_NB_PT = 52; + @Deprecated + public static final int DTMF_NB_PT = ProvisioningManager.KEY_DTMF_NB_PAYLOAD_TYPE; + /** * AMR Default encoding mode. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_AMR_DEFAULT_ENCODING_MODE}. */ - public static final int AMR_DEFAULT_MODE = 53; + @Deprecated + public static final int AMR_DEFAULT_MODE = + ProvisioningManager.KEY_AMR_DEFAULT_ENCODING_MODE; + /** * SMS Public Service Identity. * Value is in String format. + * @deprecated use {@link ProvisioningManager#KEY_SMS_PUBLIC_SERVICE_IDENTITY}. */ - public static final int SMS_PSI = 54; + @Deprecated + public static final int SMS_PSI = ProvisioningManager.KEY_SMS_PUBLIC_SERVICE_IDENTITY; + /** * Video Quality - VideoQualityFeatureValuesConstants. * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_VIDEO_QUALITY}. */ - public static final int VIDEO_QUALITY = 55; + @Deprecated + public static final int VIDEO_QUALITY = ProvisioningManager.KEY_VIDEO_QUALITY; + /** * LTE threshold. * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A. + * @deprecated use {@link ProvisioningManager#KEY_LTE_THRESHOLD_1}. */ - public static final int TH_LTE1 = 56; + @Deprecated + public static final int TH_LTE1 = ProvisioningManager.KEY_LTE_THRESHOLD_1; + /** * LTE threshold. * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2). + * @deprecated use {@link ProvisioningManager#KEY_LTE_THRESHOLD_2}. */ - public static final int TH_LTE2 = 57; + @Deprecated + public static final int TH_LTE2 = ProvisioningManager.KEY_LTE_THRESHOLD_2; + /** * LTE threshold. * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2). + * @deprecated use {@link ProvisioningManager#KEY_LTE_THRESHOLD_3}. */ - public static final int TH_LTE3 = 58; + @Deprecated + public static final int TH_LTE3 = ProvisioningManager.KEY_LTE_THRESHOLD_3; + /** * 1x threshold. * Handover from 1x to WiFi if 1x < TH1x + * @deprecated use {@link ProvisioningManager#KEY_1X_THRESHOLD}. */ - public static final int TH_1x = 59; + @Deprecated + public static final int TH_1x = ProvisioningManager.KEY_1X_THRESHOLD; + /** * WiFi threshold. * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A. + * @deprecated use {@link ProvisioningManager#KEY_WIFI_THRESHOLD_A}. */ - public static final int VOWT_A = 60; + @Deprecated + public static final int VOWT_A = ProvisioningManager.KEY_WIFI_THRESHOLD_A; + /** * WiFi threshold. * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2). + * @deprecated use {@link ProvisioningManager#KEY_WIFI_THRESHOLD_B}. */ - public static final int VOWT_B = 61; + @Deprecated + public static final int VOWT_B = ProvisioningManager.KEY_WIFI_THRESHOLD_B; + /** * LTE ePDG timer. * Device shall not handover back to LTE until the T_ePDG_LTE timer expires. + * @deprecated use {@link ProvisioningManager#KEY_LTE_EPDG_TIMER_SEC}. */ - public static final int T_EPDG_LTE = 62; + @Deprecated + public static final int T_EPDG_LTE = ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC; + /** * WiFi ePDG timer. * Device shall not handover back to WiFi until the T_ePDG_WiFi timer expires. + * @deprecated use {@link ProvisioningManager#KEY_WIFI_EPDG_TIMER_SEC}. */ - public static final int T_EPDG_WIFI = 63; + @Deprecated + public static final int T_EPDG_WIFI = ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC; + /** * 1x ePDG timer. * Device shall not re-register on 1x until the T_ePDG_1x timer expires. + * @deprecated use {@link ProvisioningManager#KEY_1X_EPDG_TIMER_SEC}. */ - public static final int T_EPDG_1X = 64; + @Deprecated + public static final int T_EPDG_1X = ProvisioningManager.KEY_1X_EPDG_TIMER_SEC; + /** * MultiEndpoint status: Enabled (1), or Disabled (0). * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_MULTIENDPOINT_ENABLED}. */ - public static final int VICE_SETTING_ENABLED = 65; + @Deprecated + public static final int VICE_SETTING_ENABLED = ProvisioningManager.KEY_MULTIENDPOINT_ENABLED; /** * RTT status: Enabled (1), or Disabled (0). * Value is in Integer format. + * @deprecated use {@link ProvisioningManager#KEY_RTT_ENABLED}. */ - public static final int RTT_SETTING_ENABLED = 66; + @Deprecated + public static final int RTT_SETTING_ENABLED = ProvisioningManager.KEY_RTT_ENABLED; // Expand the operator config items as needed here, need to change // PROVISIONED_CONFIG_END after that. diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java index e80087d8924e..15f837189843 100644 --- a/telephony/java/com/android/ims/ImsUtInterface.java +++ b/telephony/java/com/android/ims/ImsUtInterface.java @@ -16,12 +16,12 @@ package com.android.ims; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Message; import android.telephony.ims.ImsCallForwardInfo; import android.telephony.ims.ImsSsInfo; - -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.telephony.ims.stub.ImsUtImplBase; /** * Provides APIs for the supplementary service settings using IMS (Ut interface). @@ -59,47 +59,48 @@ public interface ImsUtInterface { * CDIV (Communication Diversion, 3GPP TS 24.604) * actions: target, no reply timer */ - public static final int CDIV_CF_UNCONDITIONAL = 0; - public static final int CDIV_CF_BUSY = 1; - public static final int CDIV_CF_NO_REPLY = 2; - public static final int CDIV_CF_NOT_REACHABLE = 3; + public static final int CDIV_CF_UNCONDITIONAL = ImsCallForwardInfo.CDIV_CF_REASON_UNCONDITIONAL; + public static final int CDIV_CF_BUSY = ImsCallForwardInfo.CDIV_CF_REASON_BUSY; + public static final int CDIV_CF_NO_REPLY = ImsCallForwardInfo.CDIV_CF_REASON_NO_REPLY; + public static final int CDIV_CF_NOT_REACHABLE = ImsCallForwardInfo.CDIV_CF_REASON_NOT_REACHABLE; // For CS service code: 002 - public static final int CDIV_CF_ALL = 4; + public static final int CDIV_CF_ALL = ImsCallForwardInfo.CDIV_CF_REASON_ALL; // For CS service code: 004 - public static final int CDIV_CF_ALL_CONDITIONAL = 5; + public static final int CDIV_CF_ALL_CONDITIONAL = + ImsCallForwardInfo.CDIV_CF_REASON_ALL_CONDITIONAL; // It's only supported in the IMS service (CS does not define it). // IR.92 recommends that an UE activates both the CFNRc and the CFNL // (CDIV using condition not-registered) to the same target. - public static final int CDIV_CF_NOT_LOGGED_IN = 6; + public static final int CDIV_CF_NOT_LOGGED_IN = ImsCallForwardInfo.CDIV_CF_REASON_NOT_LOGGED_IN; /** * CB (Communication Barring, 3GPP TS 24.611) */ // Barring of All Incoming Calls - public static final int CB_BAIC = 1; + public static final int CB_BAIC = ImsUtImplBase.CALL_BARRING_ALL_INCOMING; // Barring of All Outgoing Calls - public static final int CB_BAOC = 2; + public static final int CB_BAOC = ImsUtImplBase.CALL_BARRING_ALL_OUTGOING; // Barring of Outgoing International Calls - public static final int CB_BOIC = 3; + public static final int CB_BOIC = ImsUtImplBase.CALL_BARRING_OUTGOING_INTL; // Barring of Outgoing International Calls - excluding Home Country - public static final int CB_BOIC_EXHC = 4; + public static final int CB_BOIC_EXHC = ImsUtImplBase.CALL_BARRING_OUTGOING_INTL_EXCL_HOME; // Barring of Incoming Calls - when roaming - public static final int CB_BIC_WR = 5; + public static final int CB_BIC_WR = ImsUtImplBase.CALL_BLOCKING_INCOMING_WHEN_ROAMING; // Barring of Anonymous Communication Rejection (ACR) - a particular case of ICB service - public static final int CB_BIC_ACR = 6; + public static final int CB_BIC_ACR = ImsUtImplBase.CALL_BARRING_ANONYMOUS_INCOMING; // Barring of All Calls - public static final int CB_BA_ALL = 7; + public static final int CB_BA_ALL = ImsUtImplBase.CALL_BARRING_ALL; // Barring of Outgoing Services (Service Code 333 - 3GPP TS 22.030 Table B-1) - public static final int CB_BA_MO = 8; + public static final int CB_BA_MO = ImsUtImplBase.CALL_BARRING_OUTGOING_ALL_SERVICES; // Barring of Incoming Services (Service Code 353 - 3GPP TS 22.030 Table B-1) - public static final int CB_BA_MT = 9; + public static final int CB_BA_MT = ImsUtImplBase.CALL_BARRING_INCOMING_ALL_SERVICES; // Barring of Specific Incoming calls - public static final int CB_BS_MT = 10; + public static final int CB_BS_MT = ImsUtImplBase.CALL_BARRING_SPECIFIC_INCOMING_CALLS; /** * Invalid result value. */ - public static final int INVALID = (-1); + public static final int INVALID = ImsUtImplBase.INVALID_RESULT; diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index e1113eba006f..1449a62fbf35 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -15,9 +15,9 @@ */ package com.android.internal.telephony; -import com.android.internal.util.Protocol; +import android.compat.annotation.UnsupportedAppUsage; -import dalvik.annotation.compat.UnsupportedAppUsage; +import com.android.internal.util.Protocol; /** * @hide @@ -111,6 +111,9 @@ public class DctConstants { public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49; public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50; public static final int EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED = BASE + 51; + public static final int EVENT_SERVICE_STATE_CHANGED = BASE + 52; + public static final int EVENT_5G_TIMER_HYSTERESIS = BASE + 53; + public static final int EVENT_5G_TIMER_WATCHDOG = BASE + 54; /***** Constants *****/ diff --git a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl index 4e79660df479..76ebc0f3ac2f 100644 --- a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl +++ b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl @@ -23,9 +23,13 @@ import android.os.PersistableBundle; */ interface ICarrierConfigLoader { + /** @deprecated Use {@link #getConfigForSubIdWithFeature(int, String, String) instead */ @UnsupportedAppUsage PersistableBundle getConfigForSubId(int subId, String callingPackage); + PersistableBundle getConfigForSubIdWithFeature(int subId, String callingPackage, + String callingFeatureId); + void overrideConfig(int subId, in PersistableBundle overrides, boolean persistent); void notifyConfigChangedForSubId(int subId); diff --git a/telephony/java/com/android/internal/telephony/IOns.aidl b/telephony/java/com/android/internal/telephony/IOns.aidl index 2c48b6512421..76b6951f213d 100755 --- a/telephony/java/com/android/internal/telephony/IOns.aidl +++ b/telephony/java/com/android/internal/telephony/IOns.aidl @@ -83,7 +83,7 @@ interface IOns { * subscription id * */ - int getPreferredDataSubscriptionId(String callingPackage); + int getPreferredDataSubscriptionId(String callingPackage, String callingFeatureId); /** * Update availability of a list of networks in the current location. diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index 5b509b7260ba..28ef235bf398 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -24,113 +24,128 @@ import android.telephony.ImsiEncryptionInfo; */ interface IPhoneSubInfo { + /** @deprecated Use {@link #getDeviceIdWithFeature(String, String) instead */ + @UnsupportedAppUsage + String getDeviceId(String callingPackage); + /** * Retrieves the unique device ID, e.g., IMEI for GSM phones. */ - String getDeviceId(String callingPackage); + String getDeviceIdWithFeature(String callingPackage, String callingFeatureId); /** * Retrieves the unique Network Access ID */ - String getNaiForSubscriber(int subId, String callingPackage); + String getNaiForSubscriber(int subId, String callingPackage, String callingFeatureId); /** * Retrieves the unique device ID of a phone for the device, e.g., IMEI * for GSM phones. */ - String getDeviceIdForPhone(int phoneId, String callingPackage); + String getDeviceIdForPhone(int phoneId, String callingPackage, String callingFeatureId); /** * Retrieves the IMEI. */ - String getImeiForSubscriber(int subId, String callingPackage); + String getImeiForSubscriber(int subId, String callingPackage, String callingFeatureId); /** * Retrieves the software version number for the device, e.g., IMEI/SV * for GSM phones. */ - String getDeviceSvn(String callingPackage); + String getDeviceSvn(String callingPackage, String callingFeatureId); /** * Retrieves the software version number of a subId for the device, e.g., IMEI/SV * for GSM phones. */ - String getDeviceSvnUsingSubId(int subId, String callingPackage); + String getDeviceSvnUsingSubId(int subId, String callingPackage, String callingFeatureId); + + /** @deprecated Use {@link #getSubscriberIdWithFeature(String, String) instead */ + @UnsupportedAppUsage + String getSubscriberId(String callingPackage); /** * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones. */ - @UnsupportedAppUsage - String getSubscriberId(String callingPackage); + String getSubscriberIdWithFeature(String callingPackage, String callingComponenId); /** * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones. */ - String getSubscriberIdForSubscriber(int subId, String callingPackage); + String getSubscriberIdForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Retrieves the Group Identifier Level1 for GSM phones of a subId. */ - String getGroupIdLevel1ForSubscriber(int subId, String callingPackage); + String getGroupIdLevel1ForSubscriber(int subId, String callingPackage, + String callingFeatureId); + + /** @deprecared Use {@link getIccSerialNumberWithFeature(String, String)} instead */ + @UnsupportedAppUsage + String getIccSerialNumber(String callingPackage); /** * Retrieves the serial number of the ICC, if applicable. */ - @UnsupportedAppUsage - String getIccSerialNumber(String callingPackage); + String getIccSerialNumberWithFeature(String callingPackage, String callingFeatureId); /** * Retrieves the serial number of a given subId. */ - String getIccSerialNumberForSubscriber(int subId, String callingPackage); + String getIccSerialNumberForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Retrieves the phone number string for line 1. */ - String getLine1Number(String callingPackage); + String getLine1Number(String callingPackage, String callingFeatureId); /** * Retrieves the phone number string for line 1 of a subcription. */ - String getLine1NumberForSubscriber(int subId, String callingPackage); + String getLine1NumberForSubscriber(int subId, String callingPackage, String callingFeatureId); /** * Retrieves the alpha identifier for line 1. */ - String getLine1AlphaTag(String callingPackage); + String getLine1AlphaTag(String callingPackage, String callingFeatureId); /** * Retrieves the alpha identifier for line 1 of a subId. */ - String getLine1AlphaTagForSubscriber(int subId, String callingPackage); + String getLine1AlphaTagForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Retrieves MSISDN Number. */ - String getMsisdn(String callingPackage); + String getMsisdn(String callingPackage, String callingFeatureId); /** * Retrieves the Msisdn of a subId. */ - String getMsisdnForSubscriber(int subId, String callingPackage); + String getMsisdnForSubscriber(int subId, String callingPackage, String callingFeatureId); /** * Retrieves the voice mail number. */ - String getVoiceMailNumber(String callingPackage); + String getVoiceMailNumber(String callingPackage, String callingFeatureId); /** * Retrieves the voice mail number of a given subId. */ - String getVoiceMailNumberForSubscriber(int subId, String callingPackage); + String getVoiceMailNumberForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Retrieves the Carrier information used to encrypt IMSI and IMPI. */ ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int subId, int keyType, - String callingPackage); + String callingPackage); /** * Stores the Carrier information used to encrypt IMSI and IMPI. @@ -148,13 +163,14 @@ interface IPhoneSubInfo { /** * Retrieves the alpha identifier associated with the voice mail number. */ - String getVoiceMailAlphaTag(String callingPackage); + String getVoiceMailAlphaTag(String callingPackage, String callingFeatureId); /** * Retrieves the alpha identifier associated with the voice mail number * of a subId. */ - String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage); + String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Returns the IMS private user identity (IMPI) that was loaded from the ISIM. diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 45dd5811c657..c07a1711b32e 100644 --- a/telephony/java/com/android/internal/telephony/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -1,18 +1,18 @@ /* -** Copyright 2007, 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. -*/ + * Copyright 2007, 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.internal.telephony; @@ -22,7 +22,7 @@ import android.os.Bundle; import com.android.internal.telephony.SmsRawData; /** - * Interface for applications to access the ICC phone book. + * Service interface to handle SMS API requests * * See also SmsManager.java. */ @@ -542,6 +542,13 @@ interface ISms { in List<PendingIntent> deliveryIntents); /** + * Get carrier-dependent configuration values. + * + * @param subId the subscription Id + */ + Bundle getCarrierConfigValuesForSubscriber(int subId); + + /** * Create an app-only incoming SMS request for the calling package. * * If an incoming text contains the token returned by this method the provided @@ -573,7 +580,8 @@ interface ISms { * * @param destAddress the destination address to test for possible short code */ - int checkSmsShortCodeDestination(int subId, String callingApk, String destAddress, String countryIso); + int checkSmsShortCodeDestination(int subId, String callingApk, String callingFeatureId, + String destAddress, String countryIso); /** * Gets the SMSC address from (U)SIM. diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java index 020b92b410f1..ddd3457b3b4d 100644 --- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java +++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java @@ -186,6 +186,11 @@ public class ISmsImplBase extends ISms.Stub { } @Override + public Bundle getCarrierConfigValuesForSubscriber(int subId) { + throw new UnsupportedOperationException(); + } + + @Override public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent) { throw new UnsupportedOperationException(); } @@ -197,8 +202,8 @@ public class ISmsImplBase extends ISms.Stub { } @Override - public int checkSmsShortCodeDestination( - int subid, String callingApk, String destAddress, String countryIso) { + public int checkSmsShortCodeDestination(int subid, String callingPackage, + String callingFeatureId, String destAddress, String countryIso) { throw new UnsupportedOperationException(); } diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 92aab4b12330..cc02a409c16d 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -23,47 +23,56 @@ import com.android.internal.telephony.ISetOpportunisticDataCallback; interface ISub { /** * @param callingPackage The package maing the call. + * @param callingFeatureId The feature in the package * @return a list of all subscriptions in the database, this includes * all subscriptions that have been seen. */ - List<SubscriptionInfo> getAllSubInfoList(String callingPackage); + List<SubscriptionInfo> getAllSubInfoList(String callingPackage, String callingFeatureId); /** * @param callingPackage The package maing the call. + * @param callingFeatureId The feature in the package * @return the count of all subscriptions in the database, this includes * all subscriptions that have been seen. */ - int getAllSubInfoCount(String callingPackage); + int getAllSubInfoCount(String callingPackage, String callingFeatureId); /** * Get the active SubscriptionInfo with the subId key * @param subId The unique SubscriptionInfo key in database * @param callingPackage The package maing the call. + * @param callingFeatureId The feature in the package * @return SubscriptionInfo, maybe null if its not active */ - SubscriptionInfo getActiveSubscriptionInfo(int subId, String callingPackage); + SubscriptionInfo getActiveSubscriptionInfo(int subId, String callingPackage, + String callingFeatureId); /** * Get the active SubscriptionInfo associated with the iccId * @param iccId the IccId of SIM card * @param callingPackage The package maing the call. + * @param callingFeatureId The feature in the package * @return SubscriptionInfo, maybe null if its not active */ - SubscriptionInfo getActiveSubscriptionInfoForIccId(String iccId, String callingPackage); + SubscriptionInfo getActiveSubscriptionInfoForIccId(String iccId, String callingPackage, + String callingFeatureId); /** * Get the active SubscriptionInfo associated with the slotIndex * @param slotIndex the slot which the subscription is inserted * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package * @return SubscriptionInfo, null for Remote-SIMs or non-active slotIndex. */ - SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, String callingPackage); + SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, String callingPackage, + String callingFeatureId); /** * Get the SubscriptionInfo(s) of the active subscriptions. The records will be sorted * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}. * * @param callingPackage The package maing the call. + * @param callingFeatureId The feature in the package * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device. * <ul> * <li> @@ -80,13 +89,15 @@ interface ISub { * </li> * </ul> */ - List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage); + List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage, + String callingFeatureId); /** * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * @return the number of active subscriptions */ - int getActiveSubInfoCount(String callingPackage); + int getActiveSubInfoCount(String callingPackage, String callingFeatureId); /** * @return the maximum number of subscriptions this device will support at any one time. @@ -96,7 +107,8 @@ interface ISub { /** * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList */ - List<SubscriptionInfo> getAvailableSubscriptionInfoList(String callingPackage); + List<SubscriptionInfo> getAvailableSubscriptionInfoList(String callingPackage, + String callingFeatureId); /** * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList @@ -225,7 +237,8 @@ interface ISub { * Return opportunistic subscriptions that can be visible to the caller. * @return the list of opportunistic subscription info. If none exists, an empty list. */ - List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage); + List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage, + String callingFeatureId); void removeSubscriptionsFromGroup(in int[] subIdList, in ParcelUuid groupUuid, String callingPackage); @@ -233,7 +246,8 @@ interface ISub { void addSubscriptionsIntoGroup(in int[] subIdList, in ParcelUuid groupUuid, String callingPackage); - List<SubscriptionInfo> getSubscriptionsInGroup(in ParcelUuid groupUuid, String callingPackage); + List<SubscriptionInfo> getSubscriptionsInGroup(in ParcelUuid groupUuid, String callingPackage, + String callingFeatureId); int getSlotIndex(int subId); @@ -265,7 +279,8 @@ interface ISub { int setSubscriptionProperty(int subId, String propKey, String propValue); - String getSubscriptionProperty(int subId, String propKey, String callingPackage); + String getSubscriptionProperty(int subId, String propKey, String callingPackage, + String callingFeatureId); boolean setSubscriptionEnabled(boolean enable, int subId); @@ -278,11 +293,13 @@ interface ISub { */ int getSimStateForSlotIndex(int slotIndex); - boolean isActiveSubId(int subId, String callingPackage); + boolean isActiveSubId(int subId, String callingPackage, String callingFeatureId); boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow); int getActiveDataSubscriptionId(); boolean canDisablePhysicalSubscription(); + + int setUiccApplicationsEnabled(boolean enabled, int subscriptionId); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index feb1368e7d47..1f84451a35e4 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -30,6 +30,7 @@ import android.service.carrier.CarrierIdentifier; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telephony.CarrierRestrictionRules; +import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.ClientRequestStats; import android.telephony.IccOpenLogicalChannelResponse; @@ -89,29 +90,33 @@ interface ITelephony { @UnsupportedAppUsage void call(String callingPackage, String number); + /** @deprecated Use {@link #isRadioOnWithFeature(String, String) instead */ + @UnsupportedAppUsage + boolean isRadioOn(String callingPackage); + /** * Check to see if the radio is on or not. * @param callingPackage the name of the package making the call. + * @param callingFeatureId The feature in the package. * @return returns true if the radio is on. */ - boolean isRadioOn(String callingPackage); + boolean isRadioOnWithFeature(String callingPackage, String callingFeatureId); /** - * Check to see if the radio is on or not on particular subId. - * @param subId user preferred subId. - * @param callingPackage the name of the package making the call. - * @return returns true if the radio is on. + * @deprecated Use {@link #isRadioOnForSubscriberWithFeature(int, String, String) instead */ @UnsupportedAppUsage boolean isRadioOnForSubscriber(int subId, String callingPackage); /** - * Supply a pin to unlock the SIM. Blocks until a result is determined. - * @param pin The pin to check. - * @return whether the operation was a success. + * Check to see if the radio is on or not on particular subId. + * @param subId user preferred subId. + * @param callingPackage the name of the package making the call. + * @param callingFeatureId The feature in the package. + * @return returns true if the radio is on. */ - @UnsupportedAppUsage - boolean supplyPin(String pin); + boolean isRadioOnForSubscriberWithFeature(int subId, String callingPackage, String callingFeatureId); + /** * Supply a pin to unlock the SIM for particular subId. @@ -127,15 +132,6 @@ interface ITelephony { * Blocks until a result is determined. * @param puk The puk to check. * pin The new pin to be set in SIM - * @return whether the operation was a success. - */ - boolean supplyPuk(String puk, String pin); - - /** - * Supply puk to unlock the SIM and set SIM pin to new pin. - * Blocks until a result is determined. - * @param puk The puk to check. - * pin The new pin to be set in SIM * @param subId user preferred subId. * @return whether the operation was a success. */ @@ -148,15 +144,6 @@ interface ITelephony { * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code * retValue[1] = number of attempts remaining if known otherwise -1 */ - int[] supplyPinReportResult(String pin); - - /** - * Supply a pin to unlock the SIM. Blocks until a result is determined. - * Returns a specific success/error code. - * @param pin The pin to check. - * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code - * retValue[1] = number of attempts remaining if known otherwise -1 - */ int[] supplyPinReportResultForSubscriber(int subId, String pin); /** @@ -168,17 +155,6 @@ interface ITelephony { * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code * retValue[1] = number of attempts remaining if known otherwise -1 */ - int[] supplyPukReportResult(String puk, String pin); - - /** - * Supply puk to unlock the SIM and set SIM pin to new pin. - * Blocks until a result is determined. - * Returns a specific success/error code - * @param puk The puk to check - * pin The pin to check. - * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code - * retValue[1] = number of attempts remaining if known otherwise -1 - */ int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin); /** @@ -294,19 +270,20 @@ interface ITelephony { */ boolean isDataConnectivityPossible(int subId); - Bundle getCellLocation(String callingPkg); + // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client. + CellIdentity getCellLocation(String callingPkg, String callingFeatureId); /** * Returns the ISO country code equivalent of the current registered * operator's MCC (Mobile Country Code). * @see android.telephony.TelephonyManager#getNetworkCountryIso */ - String getNetworkCountryIsoForPhone(int phoneId, String callingPkg); + String getNetworkCountryIsoForPhone(int phoneId, String callingPkg, String callingFeatureId); /** * Returns the neighboring cell information of the device. */ - List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg); + List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg, String callingFeatureId); @UnsupportedAppUsage int getCallState(); @@ -370,23 +347,27 @@ interface ITelephony { /** * Returns the CDMA ERI icon index to display * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - int getCdmaEriIconIndex(String callingPackage); + int getCdmaEriIconIndex(String callingPackage, String callingFeatureId); /** * Returns the CDMA ERI icon index to display on particular subId. * @param subId user preferred subId. * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - int getCdmaEriIconIndexForSubscriber(int subId, String callingPackage); + int getCdmaEriIconIndexForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Returns the CDMA ERI icon mode, * 0 - ON * 1 - FLASHING * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - int getCdmaEriIconMode(String callingPackage); + int getCdmaEriIconMode(String callingPackage, String callingFeatureId); /** * Returns the CDMA ERI icon mode on particular subId, @@ -394,21 +375,25 @@ interface ITelephony { * 1 - FLASHING * @param subId user preferred subId. * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - int getCdmaEriIconModeForSubscriber(int subId, String callingPackage); + int getCdmaEriIconModeForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Returns the CDMA ERI text, * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - String getCdmaEriText(String callingPackage); + String getCdmaEriText(String callingPackage, String callingFeatureId); /** * Returns the CDMA ERI text for particular subId, * @param subId user preferred subId. * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - String getCdmaEriTextForSubscriber(int subId, String callingPackage); + String getCdmaEriTextForSubscriber(int subId, String callingPackage, String callingFeatureId); /** * Returns true if OTA service provisioning needs to run. @@ -451,7 +436,8 @@ interface ITelephony { * @param subId user preferred subId. * Returns the unread count of voicemails */ - int getVoiceMessageCountForSubscriber(int subId, String callingPackage); + int getVoiceMessageCountForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Returns true if current state supports both voice and data @@ -461,7 +447,7 @@ interface ITelephony { Bundle getVisualVoicemailSettings(String callingPackage, int subId); - String getVisualVoicemailPackageName(String callingPackage, int subId); + String getVisualVoicemailPackageName(String callingPackage, String callingFeatureId, int subId); // Not oneway, caller needs to make sure the vaule is set before receiving a SMS void enableVisualVoicemailSmsFilter(String callingPackage, int subId, @@ -493,29 +479,35 @@ interface ITelephony { * Returns the network type of a subId. * @param subId user preferred subId. * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - int getNetworkTypeForSubscriber(int subId, String callingPackage); + int getNetworkTypeForSubscriber(int subId, String callingPackage, String callingFeatureId); /** * Returns the network type for data transmission * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - int getDataNetworkType(String callingPackage); + int getDataNetworkType(String callingPackage, String callingFeatureId); /** * Returns the data network type of a subId * @param subId user preferred subId. * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. */ - int getDataNetworkTypeForSubscriber(int subId, String callingPackage); + int getDataNetworkTypeForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Returns the voice network type of a subId * @param subId user preferred subId. - * @param callingPackage package making the call. + * @param callingPackage package making the call.getLteOnCdmaMode + * @param callingFeatureId The feature in the package. * Returns the network type */ - int getVoiceNetworkTypeForSubscriber(int subId, String callingPackage); + int getVoiceNetworkTypeForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Return true if an ICC card is present @@ -536,10 +528,11 @@ interface ITelephony { * the mode may be unknown. * * @param callingPackage the name of the calling package + * @param callingFeatureId The feature in the package. * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE} * or {@link PHone#LTE_ON_CDMA_TRUE} */ - int getLteOnCdmaMode(String callingPackage); + int getLteOnCdmaMode(String callingPackage, String callingFeatureId); /** * Return if the current radio is LTE on CDMA. This @@ -547,21 +540,23 @@ interface ITelephony { * the mode may be unknown. * * @param callingPackage the name of the calling package + * @param callingFeatureId The feature in the package. * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE} * or {@link PHone#LTE_ON_CDMA_TRUE} */ - int getLteOnCdmaModeForSubscriber(int subId, String callingPackage); + int getLteOnCdmaModeForSubscriber(int subId, String callingPackage, String callingFeatureId); /** * Returns all observed cell information of the device. */ - List<CellInfo> getAllCellInfo(String callingPkg); + List<CellInfo> getAllCellInfo(String callingPkg, String callingFeatureId); /** * Request a cell information update for the specified subscription, * reported via the CellInfoCallback. */ - void requestCellInfoUpdate(int subId, in ICellInfoCallback cb, String callingPkg); + void requestCellInfoUpdate(int subId, in ICellInfoCallback cb, String callingPkg, + String callingFeatureId); /** * Request a cell information update for the specified subscription, @@ -569,8 +564,8 @@ interface ITelephony { * * @param workSource the requestor to whom the power consumption for this should be attributed. */ - void requestCellInfoUpdateWithWorkSource( - int subId, in ICellInfoCallback cb, in String callingPkg, in WorkSource ws); + void requestCellInfoUpdateWithWorkSource(int subId, in ICellInfoCallback cb, + in String callingPkg, String callingFeatureId, in WorkSource ws); /** * Sets minimum time in milli-seconds between onCellInfoChanged @@ -798,10 +793,11 @@ interface ITelephony { * Get the calculated preferred network type. * Used for device configuration by some CDMA operators. * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * * @return the calculated preferred network type, defined in RILConstants.java. */ - int getCalculatedPreferredNetworkType(String callingPackage); + int getCalculatedPreferredNetworkType(String callingPackage, String callingFeatureId); /* * Get the preferred network type. @@ -882,9 +878,12 @@ interface ITelephony { * Perform a radio scan and return the list of avialble networks. * * @param subId the id of the subscription. + * @param callingPackage the calling package + * @param callingFeatureId The feature in the package * @return CellNetworkScanResult containing status of scan and networks. */ - CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage); + CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage, + String callingFeatureId); /** * Perform a radio network scan and return the id of this scan. @@ -894,10 +893,11 @@ interface ITelephony { * @param messenger Callback messages will be sent using this messenger. * @param binder the binder object instantiated in TelephonyManager. * @param callingPackage the calling package + * @param callingFeatureId The feature in the package * @return An id for this scan. */ int requestNetworkScan(int subId, in NetworkScanRequest request, in Messenger messenger, - in IBinder binder, in String callingPackage); + in IBinder binder, in String callingPackage, String callingFeatureId); /** * Stop an existing radio network scan. @@ -976,8 +976,9 @@ interface ITelephony { * Get P-CSCF address from PCO after data connection is established or modified. * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. */ - String[] getPcscfAddress(String apnType, String callingPackage); + String[] getPcscfAddress(String apnType, String callingPackage, String callingFeatureId); /** * Set IMS registration state @@ -1067,9 +1068,10 @@ interface ITelephony { * * @param subId whose dialing number for line 1 is returned. * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * @return the displayed dialing number if set, or null if not set. */ - String getLine1NumberForDisplay(int subId, String callingPackage); + String getLine1NumberForDisplay(int subId, String callingPackage, String callingFeatureId); /** * Returns the displayed alphatag of the dialing number if it was set @@ -1077,10 +1079,11 @@ interface ITelephony { * * @param subId whose alphatag associated with line 1 is returned. * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * @return the displayed alphatag of the dialing number if set, or null if * not set. */ - String getLine1AlphaTagForDisplay(int subId, String callingPackage); + String getLine1AlphaTagForDisplay(int subId, String callingPackage, String callingFeatureId); /** * Return the set of subscriber IDs that should be considered "merged together" for data usage @@ -1092,7 +1095,7 @@ interface ITelephony { * * @hide */ - String[] getMergedSubscriberIds(int subId, String callingPackage); + String[] getMergedSubscriberIds(int subId, String callingPackage, String callingFeatureId); /** * @hide @@ -1191,26 +1194,29 @@ interface ITelephony { * Whether video calling has been enabled by the user. * * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * @return {@code true} if the user has enabled video calling, {@code false} otherwise. */ - boolean isVideoCallingEnabled(String callingPackage); + boolean isVideoCallingEnabled(String callingPackage, String callingFeatureId); /** * Whether the DTMF tone length can be changed. * * @param subId The subscription to use. * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * @return {@code true} if the DTMF tone length can be changed. */ - boolean canChangeDtmfToneLength(int subId, String callingPackage); + boolean canChangeDtmfToneLength(int subId, String callingPackage, String callingFeatureId); /** * Whether the device is a world phone. * * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * @return {@code true} if the devices is a world phone. */ - boolean isWorldPhone(int subId, String callingPackage); + boolean isWorldPhone(int subId, String callingPackage, String callingFeatureId); /** * Whether the phone supports TTY mode. @@ -1252,25 +1258,31 @@ interface ITelephony { */ int getImsRegTechnologyForMmTel(int subId); + /** @deprecated Use {@link #getDeviceIdWithFeature(String, String) instead */ + @UnsupportedAppUsage + String getDeviceId(String callingPackage); + /** * Returns the unique device ID of phone, for example, the IMEI for * GSM and the MEID for CDMA phones. Return null if device ID is not available. * * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ - String getDeviceId(String callingPackage); + String getDeviceIdWithFeature(String callingPackage, String callingFeatureId); /** * Returns the IMEI for the given slot. * * @param slotIndex - device slot. * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ - String getImeiForSlot(int slotIndex, String callingPackage); + String getImeiForSlot(int slotIndex, String callingPackage, String callingFeatureId); /** * Returns the Type Allocation Code from the IMEI for the given slot. @@ -1284,10 +1296,11 @@ interface ITelephony { * * @param slotIndex - device slot. * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ - String getMeidForSlot(int slotIndex, String callingPackage); + String getMeidForSlot(int slotIndex, String callingPackage, String callingFeatureId); /** * Returns the Manufacturer Code from the MEID for the given slot. @@ -1301,10 +1314,12 @@ interface ITelephony { * * @param slotIndex - device slot. * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ - String getDeviceSoftwareVersionForSlot(int slotIndex, String callingPackage); + String getDeviceSoftwareVersionForSlot(int slotIndex, String callingPackage, + String callingFeatureId); /** * Returns the subscription ID associated with the specified PhoneAccount. @@ -1315,7 +1330,7 @@ interface ITelephony { * Returns the subscription ID associated with the specified PhoneAccountHandle. */ int getSubIdForPhoneAccountHandle(in PhoneAccountHandle phoneAccountHandle, - String callingPackage); + String callingPackage, String callingFeatureId); /** * Returns the PhoneAccountHandle associated with a subscription ID. @@ -1345,9 +1360,11 @@ interface ITelephony { * Get the service state on specified subscription * @param subId Subscription id * @param callingPackage The package making the call + * @param callingFeatureId The feature in the package * @return Service state on specified subscription. */ - ServiceState getServiceStateForSubscriber(int subId, String callingPackage); + ServiceState getServiceStateForSubscriber(int subId, String callingPackage, + String callingFeatureId); /** * Returns the URI for the per-account voicemail ringtone set in Phone settings. @@ -1597,10 +1614,12 @@ interface ITelephony { * Get Client request stats which will contain statistical information * on each request made by client. * @param callingPackage package making the call. + * @param callingFeatureId The feature in the package. * @param subId Subscription index * @hide */ - List<ClientRequestStats> getClientRequestStats(String callingPackage, int subid); + List<ClientRequestStats> getClientRequestStats(String callingPackage, String callingFeatureId, + int subid); /** * Set SIM card power state. @@ -1619,7 +1638,8 @@ interface ITelephony { * @param subId subscription ID used for authentication * @param appType the icc application type, like {@link #APPTYPE_USIM} */ - String[] getForbiddenPlmns(int subId, int appType, String callingPackage); + String[] getForbiddenPlmns(int subId, int appType, String callingPackage, + String callingFeatureId); /** * Set the forbidden PLMN list from the givven app type (ex APPTYPE_USIM) on a particular @@ -1628,10 +1648,12 @@ interface ITelephony { * @param subId subId the id of the subscription * @param appType appType the uicc app type, must be USIM or SIM. * @param fplmns plmns the Forbiden plmns list that needed to be written to the SIM. - * @param content callingPackage the op Package name. + * @param callingPackage the op Package name. + * @param callingFeatureId the feature in the package. * @return number of fplmns that is successfully written to the SIM */ - int setForbiddenPlmns(int subId, int appType, in List<String> fplmns, String callingPackage); + int setForbiddenPlmns(int subId, int appType, in List<String> fplmns, String callingPackage, + String callingFeatureId); /** * Check if phone is in emergency callback mode @@ -1775,7 +1797,8 @@ interface ITelephony { * How many modems can have simultaneous data connections. * @hide */ - int getNumberOfModemsWithSimultaneousDataConnections(int subId, String callingPackage); + int getNumberOfModemsWithSimultaneousDataConnections(int subId, String callingPackage, + String callingFeatureId); /** * Return the network selection mode on the subscription with id {@code subId}. @@ -1791,7 +1814,7 @@ interface ITelephony { * Return the modem radio power state for slot index. * */ - int getRadioPowerState(int slotIndex, String callingPackage); + int getRadioPowerState(int slotIndex, String callingPackage, String callingFeatureId); // IMS specific AIDL commands, see ImsMmTelManager.java @@ -1921,7 +1944,7 @@ interface ITelephony { /** * Return the emergency number list from all the active subscriptions. */ - Map getEmergencyNumberList(String callingPackage); + Map getEmergencyNumberList(String callingPackage, String callingFeatureId); /** * Identify if the number is emergency number, based on all the active subscriptions. @@ -1954,6 +1977,17 @@ interface ITelephony { */ boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech); + /** + * Get the provisioning status for the IMS Rcs capability specified. + */ + boolean getRcsProvisioningStatusForCapability(int subId, int capability); + + /** + * Set the provisioning status for the IMS Rcs capability using the specified subscription. + */ + void setRcsProvisioningStatusForCapability(int subId, int capability, + boolean isProvisioned); + /** Is the capability and tech flagged as provisioned in the cache */ boolean isMmTelCapabilityProvisionedInCache(int subId, int capability, int tech); @@ -2021,12 +2055,13 @@ interface ITelephony { * Returns if the usage of multiple SIM cards at the same time is supported. * * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * @return {@link #MULTISIM_ALLOWED} if the device supports multiple SIMs. * {@link #MULTISIM_NOT_SUPPORTED_BY_HARDWARE} if the device does not support multiple SIMs. * {@link #MULTISIM_NOT_SUPPORTED_BY_CARRIER} in the device supports multiple SIMs, but the * functionality is restricted by the carrier. */ - int isMultiSimSupported(String callingPackage); + int isMultiSimSupported(String callingPackage, String callingFeatureId); /** * Switch configs to enable multi-sim or switch back to single-sim @@ -2038,7 +2073,8 @@ interface ITelephony { * Get if altering modems configurations will trigger reboot. * @hide */ - boolean doesSwitchMultiSimConfigTriggerReboot(int subId, String callingPackage); + boolean doesSwitchMultiSimConfigTriggerReboot(int subId, String callingPackage, + String callingFeatureId); /** * Get the mapping from logical slots to physical slots. @@ -2057,12 +2093,14 @@ interface ITelephony { */ boolean isApplicationOnUicc(int subId, int appType); - boolean isModemEnabledForSlot(int slotIndex, String callingPackage); + boolean isModemEnabledForSlot(int slotIndex, String callingPackage, String callingFeatureId); boolean isDataEnabledForApn(int apnType, int subId, String callingPackage); boolean isApnMetered(int apnType, int subId); + boolean isMvnoMatched(int subId, int mvnoType, String mvnoMatchData); + /** * Enqueue a pending sms Consumer, which will answer with the user specified selection for an * outgoing SmsManager operation. @@ -2094,4 +2132,9 @@ interface ITelephony { * Command line command to enable or disable handling of CEP data for test purposes. */ oneway void setCepEnabled(boolean isCepEnabled); + + /** + * Notify Rcs auto config received. + */ + void notifyRcsAutoConfigurationReceived(int subId, in byte[] config, boolean isCompressed); } diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java index 25f03c200610..94dfae8a858a 100644 --- a/telephony/java/com/android/internal/telephony/IccCardConstants.java +++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java @@ -15,11 +15,10 @@ */ package com.android.internal.telephony; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.telephony.TelephonyManager; -import dalvik.annotation.compat.UnsupportedAppUsage; - /** * {@hide} */ diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java index 59c39b158387..64d786391021 100644 --- a/telephony/java/com/android/internal/telephony/OperatorInfo.java +++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 888746a53244..7ec22698edb4 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -15,7 +15,7 @@ */ package com.android.internal.telephony; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 9cbcd7fc6b04..284544b7f6f2 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -16,10 +16,9 @@ package com.android.internal.telephony; +import android.compat.annotation.UnsupportedAppUsage; import android.sysprop.TelephonyProperties; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.Optional; /** @@ -555,4 +554,5 @@ public interface RILConstants { int RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG = 1101; int RIL_UNSOL_EMERGENCY_NUMBER_LIST = 1102; int RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED = 1103; + int RIL_UNSOL_REGISTRATION_FAILED = 1104; } diff --git a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java index d672642b1158..8e86ff788a08 100644 --- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java +++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java @@ -16,17 +16,16 @@ package com.android.internal.telephony; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.XmlResourceParser; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.util.SparseIntArray; import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.util.TelephonyUtils; import com.android.internal.telephony.util.XmlUtils; -import dalvik.annotation.compat.UnsupportedAppUsage; - public class Sms7BitEncodingTranslator { private static final String TAG = "Sms7BitEncodingTranslator"; @UnsupportedAppUsage diff --git a/telephony/java/com/android/internal/telephony/SmsAddress.java b/telephony/java/com/android/internal/telephony/SmsAddress.java index 2a8de8c8502e..f18256aabed4 100644 --- a/telephony/java/com/android/internal/telephony/SmsAddress.java +++ b/telephony/java/com/android/internal/telephony/SmsAddress.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public abstract class SmsAddress { // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118 diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java index dd77b0179487..ab3fdf4ebb41 100644 --- a/telephony/java/com/android/internal/telephony/SmsHeader.java +++ b/telephony/java/com/android/internal/telephony/SmsHeader.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.internal.util.HexDump; diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index e396f0c3dc89..f21f8889fedb 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.telephony.SmsMessage; import android.text.TextUtils; diff --git a/telephony/java/com/android/internal/telephony/SmsRawData.java b/telephony/java/com/android/internal/telephony/SmsRawData.java index 18727f3a14fa..9776c8f51433 100644 --- a/telephony/java/com/android/internal/telephony/SmsRawData.java +++ b/telephony/java/com/android/internal/telephony/SmsRawData.java @@ -17,7 +17,7 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 8e1a78c56e0a..eef96c4e04a3 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.content.Intent; import android.telephony.SubscriptionManager; +import android.telephony.ims.ImsManager; /** * The intents that the telephony services broadcast. @@ -172,24 +173,6 @@ public class TelephonyIntents { = "android.intent.action.ANY_DATA_STATE"; /** - * Broadcast Action: An attempt to establish a data connection has failed. - * The intent will have the following extra values:</p> - * <dl> - * <dt>phoneName</dt><dd>A string version of the phone name.</dd> - * <dt>state</dt><dd>One of {@code CONNECTED}, {@code CONNECTING}, or {code DISCONNECTED}.</dd> - * <dt>reason</dt><dd>A string indicating the reason for the failure, if available.</dd> - * </dl> - * - * <p class="note"> - * Requires the READ_PHONE_STATE permission. - * - * <p class="note">This is a protected intent that can only be sent - * by the system. - */ - public static final String ACTION_DATA_CONNECTION_FAILED - = "android.intent.action.DATA_CONNECTION_FAILED"; - - /** * Broadcast Action: The sim card state has changed. * The intent will have the following extra values:</p> * <dl> @@ -222,8 +205,6 @@ public class TelephonyIntents { public static final String ACTION_SIM_STATE_CHANGED = Intent.ACTION_SIM_STATE_CHANGED; - public static final String EXTRA_REBROADCAST_ON_UNLOCK= "rebroadcastOnUnlock"; - /** * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms * <p class="note">. @@ -241,9 +222,11 @@ public class TelephonyIntents { * <p class="note"> * This is for the OEM applications to understand about possible provisioning issues. * Used in OMA-DM applications. + * @deprecated Use {@link ImsManager#ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION} instead. */ - public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION - = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION"; + @Deprecated + public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = + ImsManager.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION; /** * Broadcast Action: A "secret code" has been entered in the dialer. Secret codes are diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 4e42c20d28db..ff70f8ba3936 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Contains a list of string constants used to get or set telephone properties diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index 1f7715b59aff..d0c8024c56fe 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -16,10 +16,11 @@ package com.android.internal.telephony.cdma; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.sysprop.TelephonyProperties; import android.telephony.PhoneNumberUtils; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.telephony.SmsCbLocation; import android.telephony.SmsCbMessage; import android.telephony.cdma.CdmaSmsCbProgramData; @@ -41,8 +42,6 @@ import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.util.BitwiseInputStream; import com.android.internal.util.HexDump; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -149,10 +148,9 @@ public class SmsMessage extends SmsMessageBase { } /** - * Create an SmsMessage from an SMS EF record. + * Creates an SmsMessage from an SMS EF record. * - * @param index Index of SMS record. This should be index in ArrayList - * returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1. + * @param index Index of SMS EF record. * @param data Record data. * @return An SmsMessage representing the record. * @@ -203,26 +201,16 @@ public class SmsMessage extends SmsMessageBase { } /** - * TODO(cleanup): why do getSubmitPdu methods take an scAddr input - * and do nothing with it? GSM allows us to specify a SC (eg, - * when responding to an SMS that explicitly requests the response - * is sent to a specific SC), or pass null to use the default - * value. Is there no similar notion in CDMA? Or do we just not - * have it hooked up? - */ - - /** - * Get an SMS-SUBMIT PDU for a destination address and a message + * Gets an SMS-SUBMIT PDU for a destination address and a message. * - * @param scAddr Service Centre address. Null means use default. - * @param destAddr Address of the recipient. - * @param message String representation of the message payload. - * @param statusReportRequested Indicates whether a report is requested for this message. - * @param smsHeader Array containing the data for the User Data Header, preceded - * by the Element Identifiers. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param scAddr Service Centre address. No use for this message. + * @param destAddr the address of the destination for the message. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is requested for this message. + * @param smsHeader array containing the data for the User Data Header, preceded by the Element + * Identifiers. + * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns + * null on encode error. * @hide */ @UnsupportedAppUsage @@ -232,18 +220,17 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a destination address and a message + * Gets an SMS-SUBMIT PDU for a destination address and a message. * - * @param scAddr Service Centre address. Null means use default. - * @param destAddr Address of the recipient. - * @param message String representation of the message payload. - * @param statusReportRequested Indicates whether a report is requested for this message. - * @param smsHeader Array containing the data for the User Data Header, preceded - * by the Element Identifiers. - * @param priority Priority level of the message - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param scAddr Service Centre address. No use for this message. + * @param destAddr the address of the destination for the message. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is requested for this message. + * @param smsHeader array containing the data for the User Data Header, preceded by the Element + * Identifiers. + * @param priority priority level of the message. + * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns + * null on encode error. * @hide */ @UnsupportedAppUsage @@ -266,16 +253,15 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a data message to a destination address and port. + * Gets an SMS-SUBMIT PDU for a data message to a destination address & port. * - * @param scAddr Service Centre address. null == use default - * @param destAddr the address of the destination for the message - * @param destPort the port to deliver the message to at the - * destination - * @param data the data for the message - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param scAddr Service Centre address. No use for this message. + * @param destAddr the address of the destination for the message. + * @param destPort the port to deliver the message to at the destination. + * @param data the data for the message. + * @param statusReportRequested indicates whether a report is requested for this message. + * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns + * null on encode error. */ @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, int destPort, @@ -306,14 +292,13 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * Gets an SMS-SUBMIT PDU for a data message to a destination address & port. * - * @param destAddr the address of the destination for the message - * @param userData the data for the message - * @param statusReportRequested Indicates whether a report is requested for this message. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param destAddr the address of the destination for the message. + * @param userData the data for the message. + * @param statusReportRequested indicates whether a report is requested for this message. + * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns + * null on encode error. */ @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String destAddr, UserData userData, @@ -322,15 +307,14 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * Gets an SMS-SUBMIT PDU for a data message to a destination address & port. * - * @param destAddr the address of the destination for the message - * @param userData the data for the message - * @param statusReportRequested Indicates whether a report is requested for this message. - * @param priority Priority level of the message - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param destAddr the address of the destination for the message. + * @param userData the data for the message. + * @param statusReportRequested indicates whether a report is requested for this message. + * @param priority Priority level of the message. + * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns + * null on encode error. */ @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String destAddr, UserData userData, @@ -1060,6 +1044,72 @@ public class SmsMessage extends SmsMessageBase { } /** + * Gets an SMS-DELIVER PDU for a originating address and a message. + * + * @param origAddr the address of the originating for the message. + * @param message string representation of the message payload. + * @param date the time stamp the message was received. + * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns + * null on encode error. + * @hide + */ + public static SubmitPdu getDeliverPdu(String origAddr, String message, long date) { + if (origAddr == null || message == null) { + return null; + } + + CdmaSmsAddress addr = CdmaSmsAddress.parse(origAddr); + if (addr == null) return null; + + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + + bearerData.messageId = 0; + + bearerData.deliveryAckReq = false; + bearerData.userAckReq = false; + bearerData.readAckReq = false; + bearerData.reportReq = false; + + bearerData.userData = new UserData(); + bearerData.userData.payloadStr = message; + + bearerData.msgCenterTimeStamp = BearerData.TimeStamp.fromMillis(date); + + byte[] encodedBearerData = BearerData.encode(bearerData); + if (encodedBearerData == null) return null; + + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(100); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeInt(SmsEnvelope.TELESERVICE_WMT); + dos.writeInt(0); // servicePresent + dos.writeInt(0); // serviceCategory + dos.write(addr.digitMode); + dos.write(addr.numberMode); + dos.write(addr.ton); // number_type + dos.write(addr.numberPlan); + dos.write(addr.numberOfDigits); + dos.write(addr.origBytes, 0, addr.origBytes.length); // digits + // Subaddress is not supported. + dos.write(0); // subaddressType + dos.write(0); // subaddr_odd + dos.write(0); // subaddr_nbr_of_digits + dos.write(encodedBearerData.length); + dos.write(encodedBearerData, 0, encodedBearerData.length); + dos.close(); + + SubmitPdu pdu = new SubmitPdu(); + pdu.encodedMessage = baos.toByteArray(); + pdu.encodedScAddress = null; + return pdu; + } catch (IOException ex) { + Rlog.e(LOG_TAG, "creating Deliver PDU failed: " + ex); + } + return null; + } + + /** * Creates byte array (pseudo pdu) from SMS object. * Note: Do not call this method more than once per object! * @hide diff --git a/telephony/java/com/android/internal/telephony/cdma/UserData.java b/telephony/java/com/android/internal/telephony/cdma/UserData.java index d960f05f3114..d7e296800a62 100644 --- a/telephony/java/com/android/internal/telephony/cdma/UserData.java +++ b/telephony/java/com/android/internal/telephony/cdma/UserData.java @@ -16,13 +16,12 @@ package com.android.internal.telephony.cdma.sms; +import android.compat.annotation.UnsupportedAppUsage; import android.util.SparseIntArray; import com.android.internal.telephony.SmsHeader; import com.android.internal.util.HexDump; -import dalvik.annotation.compat.UnsupportedAppUsage; - public class UserData { @UnsupportedAppUsage diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index e9378e7ba690..f4a96a67c3b2 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -16,8 +16,9 @@ package com.android.internal.telephony.cdma.sms; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.telephony.SmsCbCmasInfo; import android.telephony.cdma.CdmaSmsCbProgramData; import android.telephony.cdma.CdmaSmsCbProgramResults; @@ -31,8 +32,7 @@ import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.util.BitwiseInputStream; import com.android.internal.util.BitwiseOutputStream; -import dalvik.annotation.compat.UnsupportedAppUsage; - +import java.io.ByteArrayOutputStream; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -285,6 +285,33 @@ public final class BearerData { return ts; } + public static TimeStamp fromMillis(long timeInMillis) { + TimeStamp ts = new TimeStamp(); + LocalDateTime localDateTime = + Instant.ofEpochMilli(timeInMillis).atZone(ts.mZoneId).toLocalDateTime(); + int year = localDateTime.getYear(); + if (year < 1996 || year > 2095) return null; + ts.year = year; + ts.month = localDateTime.getMonthValue(); + ts.monthDay = localDateTime.getDayOfMonth(); + ts.hour = localDateTime.getHour(); + ts.minute = localDateTime.getMinute(); + ts.second = localDateTime.getSecond(); + return ts; + } + + public byte[] toByteArray() { + int year = this.year % 100; // 00 - 99 + ByteArrayOutputStream outStream = new ByteArrayOutputStream(6); + outStream.write((((year / 10) & 0x0F) << 4) | ((year % 10) & 0x0F)); + outStream.write((((month / 10) << 4) & 0xF0) | ((month % 10) & 0x0F)); + outStream.write((((monthDay / 10) << 4) & 0xF0) | ((monthDay % 10) & 0x0F)); + outStream.write((((hour / 10) << 4) & 0xF0) | ((hour % 10) & 0x0F)); + outStream.write((((minute / 10) << 4) & 0xF0) | ((minute % 10) & 0x0F)); + outStream.write((((second / 10) << 4) & 0xF0) | ((second % 10) & 0x0F)); + return outStream.toByteArray(); + } + public long toMillis() { LocalDateTime localDateTime = LocalDateTime.of(year, month + 1, monthDay, hour, minute, second); @@ -958,6 +985,12 @@ public final class BearerData { } } + private static void encodeMsgCenterTimeStamp(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException { + outStream.write(8, 6); + outStream.writeByteArray(8 * 6, bData.msgCenterTimeStamp.toByteArray()); + }; + /** * Create serialized representation for BearerData object. * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details) @@ -1022,6 +1055,10 @@ public final class BearerData { outStream.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS); encodeScpResults(bData, outStream); } + if (bData.msgCenterTimeStamp != null) { + outStream.write(8, SUBPARAM_MESSAGE_CENTER_TIME_STAMP); + encodeMsgCenterTimeStamp(bData, outStream); + } return outStream.toByteArray(); } catch (BitwiseOutputStream.AccessException ex) { Rlog.e(LOG_TAG, "BearerData encode failed: " + ex); diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java index b268ee82529b..039b1769b487 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java @@ -16,14 +16,13 @@ package com.android.internal.telephony.cdma.sms; +import android.compat.annotation.UnsupportedAppUsage; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.SmsAddress; import com.android.internal.util.HexDump; -import dalvik.annotation.compat.UnsupportedAppUsage; - public class CdmaSmsAddress extends SmsAddress { /** diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java index be1eab1d4523..964e2fb32689 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java @@ -17,10 +17,9 @@ package com.android.internal.telephony.cdma.sms; +import android.compat.annotation.UnsupportedAppUsage; import android.telephony.cdma.CdmaSmsCbProgramData; -import dalvik.annotation.compat.UnsupportedAppUsage; - public final class SmsEnvelope { /** * Message Types diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java index 19e0b2d1ba35..c2adbc214a79 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java @@ -16,13 +16,12 @@ package com.android.internal.telephony.gsm; +import android.compat.annotation.UnsupportedAppUsage; import android.telephony.PhoneNumberUtils; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.SmsAddress; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.text.ParseException; public class GsmSmsAddress extends SmsAddress { diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java index 11bc5de08c66..f29410d9fca3 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java @@ -16,13 +16,12 @@ package com.android.internal.telephony.gsm; +import android.compat.annotation.UnsupportedAppUsage; import android.telephony.SmsCbCmasInfo; import android.telephony.SmsCbEtwsInfo; import com.android.internal.telephony.SmsConstants; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.Arrays; import java.util.Locale; diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index e7b385c5444b..4538193818c1 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -25,9 +25,10 @@ import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES; import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_SEPTETS; import static com.android.internal.telephony.SmsConstants.MessageClass; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.telephony.PhoneNumberUtils; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import android.text.TextUtils; import com.android.internal.telephony.EncodeException; @@ -38,13 +39,14 @@ import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.uicc.IccUtils; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.text.ParseException; +import java.time.Instant; import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.ZonedDateTime; /** * A Short Message Service message. @@ -169,10 +171,9 @@ public class SmsMessage extends SmsMessageBase { } /** - * Create an SmsMessage from an SMS EF record. + * Creates an SmsMessage from an SMS EF record. * - * @param index Index of SMS record. This should be index in ArrayList - * returned by SmsManager.getAllMessagesFromSim + 1. + * @param index Index of SMS EF record. * @param data Record data. * @return An SmsMessage representing the record. * @@ -261,12 +262,15 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a destination address and a message + * Gets an SMS-SUBMIT PDU for a destination address and a message. * - * @param scAddress Service Centre address. Null means use default. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is reuested for this message. + * @param header a byte array containing the data for the User Data Header. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. * @hide */ @UnsupportedAppUsage @@ -279,17 +283,19 @@ public class SmsMessage extends SmsMessageBase { /** - * Get an SMS-SUBMIT PDU for a destination address and a message using the - * specified encoding. + * Gets an SMS-SUBMIT PDU for a destination address and a message using the specified encoding. * - * @param scAddress Service Centre address. Null means use default. - * @param encoding Encoding defined by constants in - * com.android.internal.telephony.SmsConstants.ENCODING_* + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is reuested for this message. + * @param header a byte array containing the data for the User Data Header. + * @param encoding encoding defined by constants in + * com.android.internal.telephony.SmsConstants.ENCODING_* * @param languageTable * @param languageShiftTable - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. * @hide */ @UnsupportedAppUsage @@ -302,18 +308,20 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a destination address and a message using the - * specified encoding. + * Gets an SMS-SUBMIT PDU for a destination address and a message using the specified encoding. * - * @param scAddress Service Centre address. Null means use default. - * @param encoding Encoding defined by constants in - * com.android.internal.telephony.SmsConstants.ENCODING_* + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is reuested for this message. + * @param header a byte array containing the data for the User Data Header. + * @param encoding encoding defined by constants in + * com.android.internal.telephony.SmsConstants.ENCODING_* * @param languageTable * @param languageShiftTable * @param validityPeriod Validity Period of the message in Minutes. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. * @hide */ @UnsupportedAppUsage @@ -485,12 +493,14 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a destination address and a message + * Gets an SMS-SUBMIT PDU for a destination address and a message. * - * @param scAddress Service Centre address. Null means use default. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is reuested for this message. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. */ @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddress, @@ -501,15 +511,15 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a destination address and a message + * Gets an SMS-SUBMIT PDU for a destination address and a message. * - * @param scAddress Service Centre address. Null means use default. - * @param destinationAddress the address of the destination for the message - * @param statusReportRequested staus report of the message Requested + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param message string representation of the message payload. + * @param statusReportRequested indicates whether a report is reuested for this message. * @param validityPeriod Validity Period of the message in Minutes. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. */ @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddress, @@ -520,16 +530,15 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * Gets an SMS-SUBMIT PDU for a data message to a destination address & port. * - * @param scAddress Service Centre address. null == use default - * @param destinationAddress the address of the destination for the message - * @param destinationPort the port to deliver the message to at the - * destination - * @param data the data for the message - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param destinationPort the port to deliver the message to at the destination. + * @param data the data for the message. + * @param statusReportRequested indicates whether a report is reuested for this message. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. */ public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, int destinationPort, byte[] data, @@ -553,8 +562,7 @@ public class SmsMessage extends SmsMessageBase { SubmitPdu ret = new SubmitPdu(); ByteArrayOutputStream bo = getSubmitPduHead( - scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, - // TP-UDHI = true + scAddress, destinationAddress, (byte) 0x41, /* TP-MTI=SMS-SUBMIT, TP-UDHI=true */ statusReportRequested, ret); // Skip encoding pdu if error occurs when create pdu head and the error will be handled // properly later on encodedMessage sanity check. @@ -581,16 +589,18 @@ public class SmsMessage extends SmsMessageBase { } /** - * Create the beginning of a SUBMIT PDU. This is the part of the - * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, - * one of which takes a byte array and the other of which takes a + * Creates the beginning of a SUBMIT PDU. + * + * This is the part of the SUBMIT PDU that is common to the two versions of + * {@link #getSubmitPdu}, one of which takes a byte array and the other of which takes a * <code>String</code>. * - * @param scAddress Service Centre address. null == use default - * @param destinationAddress the address of the destination for the message + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. * @param mtiByte - * @param ret <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. Returns null on encode error. + * @param statusReportRequested indicates whether a report is reuested for this message. + * @param ret <code>SubmitPdu</code>. + * @return a byte array of the beginning of a SUBMIT PDU. Null for invalid destinationAddress. */ @UnsupportedAppUsage private static ByteArrayOutputStream getSubmitPduHead( @@ -638,6 +648,161 @@ public class SmsMessage extends SmsMessageBase { return bo; } + /** + * Gets an SMS-DELIVER PDU for an originating address and a message. + * + * @param scAddress Service Centre address. Null means use default. + * @param originatingAddress the address of the originating for the message. + * @param message string representation of the message payload. + * @param date the time stamp the message was received. + * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the + * encoded message. Returns null on encode error. + * @hide + */ + public static SubmitPdu getDeliverPdu( + String scAddress, String originatingAddress, String message, long date) { + if (originatingAddress == null || message == null) { + return null; + } + + // Find the best encoding to use + TextEncodingDetails ted = calculateLength(message, false); + int encoding = ted.codeUnitSize; + int languageTable = ted.languageTable; + int languageShiftTable = ted.languageShiftTable; + byte[] header = null; + + if (encoding == ENCODING_7BIT && (languageTable != 0 || languageShiftTable != 0)) { + SmsHeader smsHeader = new SmsHeader(); + smsHeader.languageTable = languageTable; + smsHeader.languageShiftTable = languageShiftTable; + header = SmsHeader.toByteArray(smsHeader); + } + + SubmitPdu ret = new SubmitPdu(); + + ByteArrayOutputStream bo = new ByteArrayOutputStream(MAX_USER_DATA_BYTES + 40); + + // SMSC address with length octet, or 0 + if (scAddress == null) { + ret.encodedScAddress = null; + } else { + ret.encodedScAddress = + PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(scAddress); + } + + // TP-Message-Type-Indicator + bo.write(0); // SMS-DELIVER + + byte[] oaBytes; + + oaBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(originatingAddress); + + // Return null for invalid originating address + if (oaBytes == null) return null; + + // Originating address length in BCD digits, ignoring TON byte and pad + // TODO Should be better. + bo.write((oaBytes.length - 1) * 2 - ((oaBytes[oaBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); + + // Originating Address + bo.write(oaBytes, 0, oaBytes.length); + + // TP-Protocol-Identifier + bo.write(0); + + // User Data (and length) + byte[] userData; + try { + if (encoding == ENCODING_7BIT) { + userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header, + languageTable, languageShiftTable); + } else { // Assume UCS-2 + try { + userData = encodeUCS2(message, header); + } catch (UnsupportedEncodingException uex) { + Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex); + return null; + } + } + } catch (EncodeException ex) { + if (ex.getError() == EncodeException.ERROR_EXCEED_SIZE) { + Rlog.e(LOG_TAG, "Exceed size limitation EncodeException", ex); + return null; + } else { + // Encoding to the 7-bit alphabet failed. Let's see if we can send it as a UCS-2 + // encoded message + try { + userData = encodeUCS2(message, header); + encoding = ENCODING_16BIT; + } catch (EncodeException ex1) { + Rlog.e(LOG_TAG, "Exceed size limitation EncodeException", ex1); + return null; + } catch (UnsupportedEncodingException uex) { + Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex); + return null; + } + } + } + + if (encoding == ENCODING_7BIT) { + if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { + // Message too long + Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)"); + return null; + } + // TP-Data-Coding-Scheme + // Default encoding, uncompressed + bo.write(0x00); + } else { // Assume UCS-2 + if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) { + // Message too long + Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)"); + return null; + } + // TP-Data-Coding-Scheme + // UCS-2 encoding, uncompressed + bo.write(0x08); + } + + // TP-Service-Centre-Time-Stamp + byte[] scts = new byte[7]; + + ZonedDateTime zoneDateTime = Instant.ofEpochMilli(date).atZone(ZoneId.systemDefault()); + LocalDateTime localDateTime = zoneDateTime.toLocalDateTime(); + + // It indicates the difference, expressed in quarters of an hour, between the local time and + // GMT. + int timezoneOffset = zoneDateTime.getOffset().getTotalSeconds() / 60 / 15; + boolean negativeOffset = timezoneOffset < 0; + if (negativeOffset) { + timezoneOffset = -timezoneOffset; + } + int year = localDateTime.getYear(); + int month = localDateTime.getMonthValue(); + int day = localDateTime.getDayOfMonth(); + int hour = localDateTime.getHour(); + int minute = localDateTime.getMinute(); + int second = localDateTime.getSecond(); + + year = year > 2000 ? year - 2000 : year - 1900; + scts[0] = (byte) ((((year % 10) & 0x0F) << 4) | ((year / 10) & 0x0F)); + scts[1] = (byte) ((((month % 10) & 0x0F) << 4) | ((month / 10) & 0x0F)); + scts[2] = (byte) ((((day % 10) & 0x0F) << 4) | ((day / 10) & 0x0F)); + scts[3] = (byte) ((((hour % 10) & 0x0F) << 4) | ((hour / 10) & 0x0F)); + scts[4] = (byte) ((((minute % 10) & 0x0F) << 4) | ((minute / 10) & 0x0F)); + scts[5] = (byte) ((((second % 10) & 0x0F) << 4) | ((second / 10) & 0x0F)); + scts[6] = (byte) ((((timezoneOffset % 10) & 0x0F) << 4) | ((timezoneOffset / 10) & 0x0F)); + if (negativeOffset) { + scts[0] |= 0x08; // Negative offset + } + bo.write(scts, 0, scts.length); + + bo.write(userData, 0, userData.length); + ret.encodedMessage = bo.toByteArray(); + return ret; + } + private static class PduParser { @UnsupportedAppUsage byte mPdu[]; diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java index f2d46244d60e..0dc740194034 100644 --- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java @@ -16,17 +16,16 @@ package com.android.internal.telephony.uicc; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.graphics.Bitmap; import android.graphics.Color; -import android.telephony.Rlog; +import com.android.telephony.Rlog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.UnsupportedEncodingException; import java.util.List; diff --git a/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java b/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java new file mode 100644 index 000000000000..8a2545772b5b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java @@ -0,0 +1,47 @@ +/* + * 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 com.android.internal.telephony.util; + +import android.annotation.NonNull; +import android.os.Handler; + +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; + +/** + * An adapter {@link Executor} that posts all executed tasks onto the given + * {@link Handler}. + * + * @hide + */ +public class HandlerExecutor implements Executor { + private final Handler mHandler; + + public HandlerExecutor(@NonNull Handler handler) { + if (handler == null) { + throw new NullPointerException(); + } + mHandler = handler; + } + + @Override + public void execute(Runnable command) { + if (!mHandler.post(command)) { + throw new RejectedExecutionException(mHandler + " is shutting down"); + } + } +} diff --git a/telephony/java/com/android/telephony/Rlog.java b/telephony/java/com/android/telephony/Rlog.java new file mode 100644 index 000000000000..9d6c930de8f5 --- /dev/null +++ b/telephony/java/com/android/telephony/Rlog.java @@ -0,0 +1,154 @@ +/* + * 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.telephony; + +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; + +import com.android.internal.telephony.util.TelephonyUtils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * A copy of {@link android.telephony.Rlog} to be used within the telephony mainline module. + * + * @hide + */ +public final class Rlog { + + private static final boolean USER_BUILD = TelephonyUtils.IS_USER; + + private Rlog() { + } + + private static int log(int priority, String tag, String msg) { + return Log.logToRadioBuffer(priority, tag, msg); + } + + public static int v(String tag, String msg) { + return log(Log.VERBOSE, tag, msg); + } + + public static int v(String tag, String msg, Throwable tr) { + return log(Log.VERBOSE, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int d(String tag, String msg) { + return log(Log.DEBUG, tag, msg); + } + + public static int d(String tag, String msg, Throwable tr) { + return log(Log.DEBUG, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int i(String tag, String msg) { + return log(Log.INFO, tag, msg); + } + + public static int i(String tag, String msg, Throwable tr) { + return log(Log.INFO, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int w(String tag, String msg) { + return log(Log.WARN, tag, msg); + } + + public static int w(String tag, String msg, Throwable tr) { + return log(Log.WARN, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int w(String tag, Throwable tr) { + return log(Log.WARN, tag, Log.getStackTraceString(tr)); + } + + public static int e(String tag, String msg) { + return log(Log.ERROR, tag, msg); + } + + public static int e(String tag, String msg, Throwable tr) { + return log(Log.ERROR, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int println(int priority, String tag, String msg) { + return log(priority, tag, msg); + } + + public static boolean isLoggable(String tag, int level) { + return Log.isLoggable(tag, level); + } + + /** + * Redact personally identifiable information for production users. + * @param tag used to identify the source of a log message + * @param pii the personally identifiable information we want to apply secure hash on. + * @return If tag is loggable in verbose mode or pii is null, return the original input. + * otherwise return a secure Hash of input pii + */ + public static String pii(String tag, Object pii) { + String val = String.valueOf(pii); + if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) { + return val; + } + return "[" + secureHash(val.getBytes()) + "]"; + } + + /** + * Redact personally identifiable information for production users. + * @param enablePiiLogging set when caller explicitly want to enable sensitive logging. + * @param pii the personally identifiable information we want to apply secure hash on. + * @return If enablePiiLogging is set to true or pii is null, return the original input. + * otherwise return a secure Hash of input pii + */ + public static String pii(boolean enablePiiLogging, Object pii) { + String val = String.valueOf(pii); + if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) { + return val; + } + return "[" + secureHash(val.getBytes()) + "]"; + } + + /** + * Returns a secure hash (using the SHA1 algorithm) of the provided input. + * + * @return "****" if the build type is user, otherwise the hash + * @param input the bytes for which the secure hash should be computed. + */ + private static String secureHash(byte[] input) { + // Refrain from logging user personal information in user build. + if (USER_BUILD) { + return "****"; + } + + MessageDigest messageDigest; + + try { + messageDigest = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + return "####"; + } + + byte[] result = messageDigest.digest(input); + return Base64.encodeToString( + result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP); + } +} diff --git a/test-base/hiddenapi/Android.bp b/test-base/hiddenapi/Android.bp index c4e0fab4a1a8..c202467517aa 100644 --- a/test-base/hiddenapi/Android.bp +++ b/test-base/hiddenapi/Android.bp @@ -25,5 +25,8 @@ java_library { srcs: ["src/**/*.java"], - libs: ["android.test.base"], + libs: [ + "android.test.base", + "unsupportedappusage", + ], } diff --git a/test-base/hiddenapi/src/android/test/AndroidTestCase.java b/test-base/hiddenapi/src/android/test/AndroidTestCase.java index 2b9beb160110..fcb8d432a631 100644 --- a/test-base/hiddenapi/src/android/test/AndroidTestCase.java +++ b/test-base/hiddenapi/src/android/test/AndroidTestCase.java @@ -16,7 +16,7 @@ package android.test; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import junit.framework.TestCase; diff --git a/test-base/hiddenapi/src/android/test/InstrumentationTestCase.java b/test-base/hiddenapi/src/android/test/InstrumentationTestCase.java index 139cd18a176c..a48a56c612d6 100644 --- a/test-base/hiddenapi/src/android/test/InstrumentationTestCase.java +++ b/test-base/hiddenapi/src/android/test/InstrumentationTestCase.java @@ -16,7 +16,7 @@ package android.test; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import junit.framework.TestCase; diff --git a/test-base/hiddenapi/src/junit/framework/TestCase.java b/test-base/hiddenapi/src/junit/framework/TestCase.java index 5a5486108a7a..59fbe2b94561 100644 --- a/test-base/hiddenapi/src/junit/framework/TestCase.java +++ b/test-base/hiddenapi/src/junit/framework/TestCase.java @@ -16,7 +16,7 @@ package junit.framework; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Stub only diff --git a/test-base/hiddenapi/src/junit/framework/TestSuite.java b/test-base/hiddenapi/src/junit/framework/TestSuite.java index 368c661dbfa4..32305c9149c0 100644 --- a/test-base/hiddenapi/src/junit/framework/TestSuite.java +++ b/test-base/hiddenapi/src/junit/framework/TestSuite.java @@ -16,7 +16,7 @@ package junit.framework; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.lang.reflect.Method; diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp new file mode 100644 index 000000000000..4f7569d4f451 --- /dev/null +++ b/tests/TelephonyCommonTests/Android.bp @@ -0,0 +1,49 @@ +// +// 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. +// + +android_test { + name: "TelephonyCommonTests", + srcs: [ + ":framework-telephony-common-sources", + "**/*.java", + ], + static_libs: [ + "mockito-target-extended", + "androidx.test.rules", + "truth-prebuilt", + "platform-test-annotations", + "androidx.core_core", + "androidx.fragment_fragment", + "androidx.test.ext.junit" + ], + + jni_libs: ["libdexmakerjvmtiagent"], + + // We need to rename SmsApplication to the test package or else it'll get clobbered by the + // hidden api checker + jarjar_rules: "jarjar-rules.txt", + + // Uncomment this and comment out the jarjar rule if you want to attach a debugger and step + // through the renamed classes. + // platform_apis: true, + + libs: [ + "android.test.runner", + "android.test.mock", + "android.test.base", + "unsupportedappusage", + ], +} diff --git a/tests/TelephonyCommonTests/AndroidManifest.xml b/tests/TelephonyCommonTests/AndroidManifest.xml new file mode 100644 index 000000000000..63f38c6af2cb --- /dev/null +++ b/tests/TelephonyCommonTests/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.internal.telephony.tests" + android:debuggable="true"> + + <application android:label="TelephonyCommonTests" + android:debuggable="true"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.internal.telephony.tests" + android:label="Telephony common tests" + android:debuggable="true"/> +</manifest> diff --git a/tests/TelephonyCommonTests/AndroidTest.xml b/tests/TelephonyCommonTests/AndroidTest.xml new file mode 100644 index 000000000000..e9fdabcaf136 --- /dev/null +++ b/tests/TelephonyCommonTests/AndroidTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs Telephony Common Test Cases."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="TelephonyCommonTests.apk" /> + </target_preparer> + + <option name="test-tag" value="TelephonyCommonTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.internal.telephony.tests" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + </test> +</configuration> diff --git a/tests/TelephonyCommonTests/jarjar-rules.txt b/tests/TelephonyCommonTests/jarjar-rules.txt new file mode 100644 index 000000000000..4d1115f3c56c --- /dev/null +++ b/tests/TelephonyCommonTests/jarjar-rules.txt @@ -0,0 +1,3 @@ +rule com.android.internal.telephony.SmsApplication* com.android.internal.telephony.tests.SmsApplication@1 +rule android.telephony.PackageChangeReceiver* com.android.internal.telephony.tests.PackageChangeReceiver@1 +rule com.android.internal.os.BackgroundThread* com.android.internal.telephony.tests.BackgroundThread@1 diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java new file mode 100644 index 000000000000..83fd20803ed8 --- /dev/null +++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java @@ -0,0 +1,291 @@ +/* + * 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 com.android.internal.telephony.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNotNull; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.app.AppOpsManager; +import android.app.role.RoleManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.net.Uri; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Telephony; +import android.telephony.TelephonyManager; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.internal.telephony.SmsApplication; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Unit tests for the {@link SmsApplication} utility class + */ +@RunWith(AndroidJUnit4.class) +public class SmsApplicationTest { + private static final ComponentName TEST_COMPONENT_NAME = + ComponentName.unflattenFromString("com.android.test/.TestSmsApp"); + private static final String MMS_RECEIVER_NAME = "TestMmsReceiver"; + private static final String RESPOND_VIA_SMS_NAME = "TestRespondViaSmsHandler"; + private static final String SEND_TO_NAME = "TestSendTo"; + private static final int SMS_APP_UID = 10001; + + private static final int FAKE_PHONE_UID = 10002; + private static final int FAKE_MMS_UID = 10003; + private static final int FAKE_BT_UID = 10004; + private static final int FAKE_TELEPHONY_PROVIDER_UID = 10005; + + private static final String[] APP_OPS_TO_CHECK = { + AppOpsManager.OPSTR_READ_SMS, + AppOpsManager.OPSTR_WRITE_SMS, + AppOpsManager.OPSTR_RECEIVE_SMS, + AppOpsManager.OPSTR_RECEIVE_WAP_PUSH, + AppOpsManager.OPSTR_SEND_SMS, + AppOpsManager.OPSTR_READ_CELL_BROADCASTS + }; + + private static final Set<String> SCHEMES_FOR_PREFERRED_APP = Arrays.stream(new String[]{ + "mms", + "mmsto", + "sms", + "smsto" + }).collect(Collectors.toSet()); + + @Mock private Context mContext; + @Mock private TelephonyManager mTelephonyManager; + @Mock private RoleManager mRoleManager; + @Mock private PackageManager mPackageManager; + @Mock private AppOpsManager mAppOpsManager; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + when(mContext.getSystemService(Context.ROLE_SERVICE)).thenReturn(mRoleManager); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager); + when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager); + when(mContext.createContextAsUser(isNotNull(), anyInt())).thenReturn(mContext); + + doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0))) + .when(mPackageManager) + .queryBroadcastReceiversAsUser(nullable(Intent.class), anyInt(), + nullable(UserHandle.class)); + doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0))) + .when(mPackageManager) + .queryIntentActivitiesAsUser(nullable(Intent.class), anyInt(), + nullable(UserHandle.class)); + doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0))) + .when(mPackageManager) + .queryIntentServicesAsUser(nullable(Intent.class), anyInt(), + nullable(UserHandle.class)); + + when(mTelephonyManager.isSmsCapable()).thenReturn(true); + when(mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)).thenReturn(true); + when(mRoleManager.getDefaultSmsPackage(anyInt())) + .thenReturn(TEST_COMPONENT_NAME.getPackageName()); + + for (String opStr : APP_OPS_TO_CHECK) { + when(mAppOpsManager.unsafeCheckOp( + opStr, SMS_APP_UID, TEST_COMPONENT_NAME.getPackageName())) + .thenReturn(AppOpsManager.MODE_ALLOWED); + } + } + + @Test + public void testGetDefaultSmsApplication() { + assertEquals(TEST_COMPONENT_NAME, + SmsApplication.getDefaultSmsApplicationAsUser(mContext, false, 0)); + } + + @Test + public void testGetDefaultSmsApplicationWithAppOpsFix() throws Exception { + when(mAppOpsManager.unsafeCheckOp(AppOpsManager.OPSTR_READ_SMS, SMS_APP_UID, + TEST_COMPONENT_NAME.getPackageName())) + .thenReturn(AppOpsManager.MODE_IGNORED); + setupPackageInfosForCoreApps(); + + assertEquals(TEST_COMPONENT_NAME, + SmsApplication.getDefaultSmsApplicationAsUser(mContext, true, 0)); + verify(mAppOpsManager, atLeastOnce()).setUidMode(AppOpsManager.OPSTR_READ_SMS, SMS_APP_UID, + AppOpsManager.MODE_ALLOWED); + } + + @Test + public void testPackageChanged() throws Exception { + setupPackageInfosForCoreApps(); + SmsApplication.initSmsPackageMonitor(mContext); + verify(mContext).createContextAsUser(eq(UserHandle.ALL), anyInt()); + ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mContext).registerReceiver(captor.capture(), isNotNull(), + isNull(), nullable(Handler.class)); + BroadcastReceiver smsPackageMonitor = captor.getValue(); + + Intent packageChangedIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED); + packageChangedIntent.setData( + Uri.fromParts("package", TEST_COMPONENT_NAME.getPackageName(), null)); + smsPackageMonitor.onReceive(mContext, packageChangedIntent); + + ArgumentCaptor<IntentFilter> intentFilterCaptor = + ArgumentCaptor.forClass(IntentFilter.class); + verify(mPackageManager, times(SCHEMES_FOR_PREFERRED_APP.size())) + .replacePreferredActivity(intentFilterCaptor.capture(), + eq(IntentFilter.MATCH_CATEGORY_SCHEME + | IntentFilter.MATCH_ADJUSTMENT_NORMAL), + isNotNull(List.class), + eq(new ComponentName(TEST_COMPONENT_NAME.getPackageName(), SEND_TO_NAME))); + + Set<String> capturedSchemes = intentFilterCaptor.getAllValues().stream() + .map(intentFilter -> intentFilter.getDataScheme(0)) + .collect(Collectors.toSet()); + assertEquals(SCHEMES_FOR_PREFERRED_APP.size(), capturedSchemes.size()); + assertTrue(SCHEMES_FOR_PREFERRED_APP.containsAll(capturedSchemes)); + } + + private void setupPackageInfosForCoreApps() throws Exception { + PackageInfo phonePackageInfo = new PackageInfo(); + ApplicationInfo phoneApplicationInfo = new ApplicationInfo(); + phoneApplicationInfo.uid = FAKE_PHONE_UID; + phonePackageInfo.applicationInfo = phoneApplicationInfo; + when(mPackageManager.getPackageInfo(eq(SmsApplication.PHONE_PACKAGE_NAME), anyInt())) + .thenReturn(phonePackageInfo); + + PackageInfo mmsPackageInfo = new PackageInfo(); + ApplicationInfo mmsApplicationInfo = new ApplicationInfo(); + mmsApplicationInfo.uid = FAKE_MMS_UID; + mmsPackageInfo.applicationInfo = mmsApplicationInfo; + when(mPackageManager.getPackageInfo(eq(SmsApplication.MMS_SERVICE_PACKAGE_NAME), anyInt())) + .thenReturn(mmsPackageInfo); + + PackageInfo bluetoothPackageInfo = new PackageInfo(); + ApplicationInfo bluetoothApplicationInfo = new ApplicationInfo(); + bluetoothApplicationInfo.uid = FAKE_BT_UID; + bluetoothPackageInfo.applicationInfo = bluetoothApplicationInfo; + when(mPackageManager.getPackageInfo(eq(SmsApplication.BLUETOOTH_PACKAGE_NAME), anyInt())) + .thenReturn(bluetoothPackageInfo); + + PackageInfo telephonyProviderPackageInfo = new PackageInfo(); + ApplicationInfo telephonyProviderApplicationInfo = new ApplicationInfo(); + telephonyProviderApplicationInfo.uid = FAKE_TELEPHONY_PROVIDER_UID; + telephonyProviderPackageInfo.applicationInfo = telephonyProviderApplicationInfo; + when(mPackageManager.getPackageInfo( + eq(SmsApplication.TELEPHONY_PROVIDER_PACKAGE_NAME), anyInt())) + .thenReturn(telephonyProviderPackageInfo); + } + + private List<ResolveInfo> getResolveInfosForIntent(Intent intent) { + switch (intent.getAction()) { + case Telephony.Sms.Intents.SMS_DELIVER_ACTION: + return Collections.singletonList(makeSmsDeliverResolveInfo()); + case Telephony.Sms.Intents.WAP_PUSH_DELIVER_ACTION: + return Collections.singletonList(makeWapPushResolveInfo()); + case TelephonyManager.ACTION_RESPOND_VIA_MESSAGE: + return Collections.singletonList(makeRespondViaMessageResolveInfo()); + case Intent.ACTION_SENDTO: + return Collections.singletonList(makeSendToResolveInfo()); + } + return Collections.emptyList(); + } + + private ApplicationInfo makeSmsApplicationInfo() { + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.uid = SMS_APP_UID; + return applicationInfo; + } + + private ResolveInfo makeSmsDeliverResolveInfo() { + ResolveInfo info = new ResolveInfo(); + ActivityInfo activityInfo = new ActivityInfo(); + activityInfo.applicationInfo = makeSmsApplicationInfo(); + + activityInfo.permission = Manifest.permission.BROADCAST_SMS; + activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName(); + activityInfo.name = TEST_COMPONENT_NAME.getClassName(); + + info.activityInfo = activityInfo; + return info; + } + + private ResolveInfo makeWapPushResolveInfo() { + ResolveInfo info = new ResolveInfo(); + ActivityInfo activityInfo = new ActivityInfo(); + + activityInfo.permission = Manifest.permission.BROADCAST_WAP_PUSH; + activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName(); + activityInfo.name = MMS_RECEIVER_NAME; + + info.activityInfo = activityInfo; + return info; + } + + private ResolveInfo makeRespondViaMessageResolveInfo() { + ResolveInfo info = new ResolveInfo(); + ServiceInfo serviceInfo = new ServiceInfo(); + + serviceInfo.permission = Manifest.permission.SEND_RESPOND_VIA_MESSAGE; + serviceInfo.packageName = TEST_COMPONENT_NAME.getPackageName(); + serviceInfo.name = RESPOND_VIA_SMS_NAME; + + info.serviceInfo = serviceInfo; + return info; + } + + private ResolveInfo makeSendToResolveInfo() { + ResolveInfo info = new ResolveInfo(); + ActivityInfo activityInfo = new ActivityInfo(); + + activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName(); + activityInfo.name = SEND_TO_NAME; + + info.activityInfo = activityInfo; + return info; + } +} diff --git a/tests/libs-permissions/Android.bp b/tests/libs-permissions/Android.bp index 330bfc9022df..66a1f83dc308 100644 --- a/tests/libs-permissions/Android.bp +++ b/tests/libs-permissions/Android.bp @@ -2,6 +2,7 @@ java_library { name: "com.android.test.libs.product", installable: true, product_specific: true, + sdk_version: "current", srcs: ["product/java/**/*.java"], required: ["com.android.test.libs.product.xml"], } diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING new file mode 100644 index 000000000000..a7853b68c1c1 --- /dev/null +++ b/tests/net/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "postsubmit": [ + { + "name": "FrameworksNetIntegrationTests" + } + ] +}
\ No newline at end of file diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java index eed7159ffddc..ca4ba63142a2 100644 --- a/tests/net/common/java/android/net/CaptivePortalTest.java +++ b/tests/net/common/java/android/net/CaptivePortalTest.java @@ -44,6 +44,11 @@ public class CaptivePortalTest { } @Override + public void appRequest(final int request) throws RemoteException { + mCode = request; + } + + @Override public void logEvent(int eventId, String packageName) throws RemoteException { mCode = eventId; mPackageName = packageName; @@ -80,6 +85,12 @@ public class CaptivePortalTest { } @Test + public void testReevaluateNetwork() { + final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.reevaluateNetwork()); + assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED); + } + + @Test public void testLogEvent() { final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent( MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY, diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java index a7eef055a71c..3f311c951c7e 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/tests/net/common/java/android/net/LinkPropertiesTest.java @@ -38,6 +38,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet4Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; @@ -65,6 +66,7 @@ public class LinkPropertiesTest { private static final InetAddress GATEWAY62 = address("fe80::6:22%lo"); private static final InetAddress TESTIPV4ADDR = address("192.168.47.42"); private static final InetAddress TESTIPV6ADDR = address("fe80::7:33%43"); + private static final Inet4Address DHCPSERVER = (Inet4Address) address("192.0.2.1"); private static final String NAME = "qmi0"; private static final String DOMAINS = "google.com"; private static final String PRIV_DNS_SERVER_NAME = "private.dns.com"; @@ -73,6 +75,9 @@ public class LinkPropertiesTest { private static final LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32); private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128); private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64"); + private static final Uri CAPPORT_API_URL = Uri.parse("https://test.example.com/capportapi"); + private static final CaptivePortalData CAPPORT_DATA = new CaptivePortalData.Builder() + .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build(); private static InetAddress address(String addrString) { return InetAddresses.parseNumericAddress(addrString); @@ -93,11 +98,14 @@ public class LinkPropertiesTest { assertNull(lp.getHttpProxy()); assertNull(lp.getTcpBufferSizes()); assertNull(lp.getNat64Prefix()); + assertNull(lp.getDhcpServerAddress()); assertFalse(lp.isProvisioned()); assertFalse(lp.isIpv4Provisioned()); assertFalse(lp.isIpv6Provisioned()); assertFalse(lp.isPrivateDnsActive()); assertFalse(lp.isWakeOnLanSupported()); + assertNull(lp.getCaptivePortalApiUrl()); + assertNull(lp.getCaptivePortalData()); } private LinkProperties makeTestObject() { @@ -119,7 +127,10 @@ public class LinkPropertiesTest { lp.setMtu(MTU); lp.setTcpBufferSizes(TCP_BUFFER_SIZES); lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96")); + lp.setDhcpServerAddress(DHCPSERVER); lp.setWakeOnLanSupported(true); + lp.setCaptivePortalApiUrl(CAPPORT_API_URL); + lp.setCaptivePortalData(CAPPORT_DATA); return lp; } @@ -161,6 +172,12 @@ public class LinkPropertiesTest { assertTrue(source.isIdenticalWakeOnLan(target)); assertTrue(target.isIdenticalWakeOnLan(source)); + assertTrue(source.isIdenticalCaptivePortalApiUrl(target)); + assertTrue(target.isIdenticalCaptivePortalApiUrl(source)); + + assertTrue(source.isIdenticalCaptivePortalData(target)); + assertTrue(target.isIdenticalCaptivePortalData(source)); + // Check result of equals(). assertTrue(source.equals(target)); assertTrue(target.equals(source)); @@ -959,12 +976,22 @@ public class LinkPropertiesTest { source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96")); source.setWakeOnLanSupported(true); + source.setCaptivePortalApiUrl(CAPPORT_API_URL); + source.setCaptivePortalData(CAPPORT_DATA); + + source.setDhcpServerAddress((Inet4Address) GATEWAY1); final LinkProperties stacked = new LinkProperties(); stacked.setInterfaceName("test-stacked"); source.addStackedLink(stacked); - assertParcelSane(source, 15 /* fieldCount */); + assertParcelSane(source.makeSensitiveFieldsParcelingCopy(), 18 /* fieldCount */); + + // Verify that without using a sensitiveFieldsParcelingCopy, sensitive fields are cleared. + final LinkProperties sanitized = new LinkProperties(source); + sanitized.setCaptivePortalApiUrl(null); + sanitized.setCaptivePortalData(null); + assertEquals(sanitized, parcelingRoundTrip(source)); } @Test @@ -1091,6 +1118,15 @@ public class LinkPropertiesTest { } @Test + public void testDhcpServerAddress() { + final LinkProperties lp = makeTestObject(); + assertEquals(DHCPSERVER, lp.getDhcpServerAddress()); + + lp.clear(); + assertNull(lp.getDhcpServerAddress()); + } + + @Test public void testWakeOnLanSupported() { final LinkProperties lp = makeTestObject(); assertTrue(lp.isWakeOnLanSupported()); @@ -1098,4 +1134,22 @@ public class LinkPropertiesTest { lp.clear(); assertFalse(lp.isWakeOnLanSupported()); } + + @Test + public void testCaptivePortalApiUrl() { + final LinkProperties lp = makeTestObject(); + assertEquals(CAPPORT_API_URL, lp.getCaptivePortalApiUrl()); + + lp.clear(); + assertNull(lp.getCaptivePortalApiUrl()); + } + + @Test + public void testCaptivePortalData() { + final LinkProperties lp = makeTestObject(); + assertEquals(CAPPORT_DATA, lp.getCaptivePortalData()); + + lp.clear(); + assertNull(lp.getCaptivePortalData()); + } } diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp index 7d9b7b756ae3..874bd4b97df1 100644 --- a/tests/net/integration/Android.bp +++ b/tests/net/integration/Android.bp @@ -36,6 +36,7 @@ android_test { "services.net", "testables", ], + test_suites: ["device-tests"], use_embedded_native_libs: true, jni_libs: [ // For mockito extended diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index 1e8d83c3c6cd..1c6920986318 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; @@ -35,10 +36,10 @@ import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; -import android.net.NetworkFactory; import android.net.NetworkInfo; -import android.net.NetworkMisc; +import android.net.NetworkProvider; import android.net.NetworkSpecifier; import android.net.SocketKeepalive; import android.net.UidRange; @@ -74,6 +75,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { final String typeName = ConnectivityManager.getNetworkTypeName(type); mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock"); mNetworkCapabilities = new NetworkCapabilities(); + mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED); mNetworkCapabilities.addTransportType(transport); switch (transport) { case TRANSPORT_ETHERNET: @@ -114,7 +116,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) { super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag, wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore, - new NetworkMisc(), NetworkFactory.SerialNumber.NONE); + new NetworkAgentConfig(), NetworkProvider.ID_NONE); mWrapper = wrapper; } @@ -206,13 +208,11 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { } public void suspend() { - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); + removeCapability(NET_CAPABILITY_NOT_SUSPENDED); } public void resume() { - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); + addCapability(NET_CAPABILITY_NOT_SUSPENDED); } public void disconnect() { @@ -222,7 +222,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { @Override public Network getNetwork() { - return new Network(mNetworkAgent.netId); + return mNetworkAgent.network; } public void expectPreventReconnectReceived(long timeoutMs) { diff --git a/tests/net/java/android/net/CaptivePortalDataTest.kt b/tests/net/java/android/net/CaptivePortalDataTest.kt new file mode 100644 index 000000000000..00714382684f --- /dev/null +++ b/tests/net/java/android/net/CaptivePortalDataTest.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net + +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.assertParcelSane +import com.android.testutils.assertParcelingIsLossless +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CaptivePortalDataTest { + private val data = CaptivePortalData.Builder() + .setRefreshTime(123L) + .setUserPortalUrl(Uri.parse("https://portal.example.com/test")) + .setVenueInfoUrl(Uri.parse("https://venue.example.com/test")) + .setSessionExtendable(true) + .setBytesRemaining(456L) + .setExpiryTime(789L) + .setCaptive(true) + .build() + + private fun makeBuilder() = CaptivePortalData.Builder(data) + + @Test + fun testParcelUnparcel() { + assertParcelSane(data, fieldCount = 7) + + assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build()) + assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build()) + } + + @Test + fun testEquals() { + assertEquals(data, makeBuilder().build()) + + assertNotEqualsAfterChange { it.setRefreshTime(456L) } + assertNotEqualsAfterChange { it.setUserPortalUrl(Uri.parse("https://example.com/")) } + assertNotEqualsAfterChange { it.setUserPortalUrl(null) } + assertNotEqualsAfterChange { it.setVenueInfoUrl(Uri.parse("https://example.com/")) } + assertNotEqualsAfterChange { it.setVenueInfoUrl(null) } + assertNotEqualsAfterChange { it.setSessionExtendable(false) } + assertNotEqualsAfterChange { it.setBytesRemaining(789L) } + assertNotEqualsAfterChange { it.setExpiryTime(12L) } + assertNotEqualsAfterChange { it.setCaptive(false) } + } + + private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) = + CaptivePortalData.Builder(this).apply { mutator(this) }.build() + + private fun assertNotEqualsAfterChange(mutator: (CaptivePortalData.Builder) -> Unit) { + assertNotEquals(data, data.mutate(mutator)) + } +}
\ No newline at end of file diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index c16a0f446651..33d77d288e15 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -64,15 +64,15 @@ public class NetworkStatsTest { @Test public void testFindIndex() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12); assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, @@ -94,21 +94,21 @@ public class NetworkStatsTest { @Test public void testFindIndexHinted() { final NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12) - .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12); // verify that we correctly find across regardless of hinting @@ -143,27 +143,27 @@ public class NetworkStatsTest { assertEquals(0, stats.size()); assertEquals(4, stats.internalSize()); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5); assertEquals(4, stats.size()); assertEquals(4, stats.internalSize()); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11); assertEquals(9, stats.size()); @@ -193,8 +193,8 @@ public class NetworkStatsTest { public void testCombineExisting() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 10); - stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10); - stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2); + stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10); + stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2); stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L, -128L, -1L, -1); @@ -215,12 +215,12 @@ public class NetworkStatsTest { @Test public void testSubtractIdenticalData() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats result = after.subtract(before); @@ -234,12 +234,12 @@ public class NetworkStatsTest { @Test public void testSubtractIdenticalRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20); final NetworkStats result = after.subtract(before); @@ -253,13 +253,13 @@ public class NetworkStatsTest { @Test public void testSubtractNewRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12) + .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); final NetworkStats result = after.subtract(before); @@ -275,11 +275,11 @@ public class NetworkStatsTest { @Test public void testSubtractMissingRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); + .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) + .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); final NetworkStats after = new NetworkStats(TEST_START, 1) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); + .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); final NetworkStats result = after.subtract(before); @@ -293,40 +293,40 @@ public class NetworkStatsTest { @Test public void testTotalBytes() throws Exception { final NetworkStats iface = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); assertEquals(384L, iface.getTotalBytes()); final NetworkStats uidSet = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidSet.getTotalBytes()); final NetworkStats uidTag = new NetworkStats(TEST_START, 6) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); assertEquals(64L, uidTag.getTotalBytes()); final NetworkStats uidMetered = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidMetered.getTotalBytes()); final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidRoaming.getTotalBytes()); } @@ -343,11 +343,11 @@ public class NetworkStatsTest { @Test public void testGroupedByIfaceAll() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 3) - .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L) - .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, + .addEntry(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L); final NetworkStats grouped = uidStats.groupedByIface(); @@ -361,19 +361,19 @@ public class NetworkStatsTest { @Test public void testGroupedByIface() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 7) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L); final NetworkStats grouped = uidStats.groupedByIface(); @@ -390,19 +390,19 @@ public class NetworkStatsTest { @Test public void testAddAllValues() { final NetworkStats first = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, + .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); final NetworkStats second = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, + .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); first.combineAllValues(second); @@ -421,19 +421,19 @@ public class NetworkStatsTest { @Test public void testGetTotal() { final NetworkStats stats = new NetworkStats(TEST_START, 7) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L,32L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L); assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L); @@ -459,7 +459,7 @@ public class NetworkStatsTest { assertEquals(0, after.size()); // Test 1 item stats. - before.addValues(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L); + before.addEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L); after = before.clone(); after.removeUids(new int[0]); assertEquals(1, after.size()); @@ -469,12 +469,12 @@ public class NetworkStatsTest { assertEquals(0, after.size()); // Append remaining test items. - before.addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L); + before.addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L); assertEquals(7, before.size()); // Test remove with empty uid list. @@ -505,12 +505,12 @@ public class NetworkStatsTest { @Test public void testClone() throws Exception { final NetworkStats original = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); // make clone and mutate original final NetworkStats clone = original.clone(); - original.addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L); + original.addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L); assertEquals(3, original.size()); assertEquals(2, clone.size()); @@ -523,8 +523,8 @@ public class NetworkStatsTest { public void testAddWhenEmpty() throws Exception { final NetworkStats red = new NetworkStats(TEST_START, -1); final NetworkStats blue = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); // We're mostly checking that we don't crash red.combineAllValues(blue); @@ -537,39 +537,39 @@ public class NetworkStatsTest { final String underlyingIface = "wlan0"; final int testTag1 = 8888; NetworkStats delta = new NetworkStats(TEST_START, 17) - .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L) - .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) - .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L) - .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L) - // VPN package also uses some traffic through unprotected network. - .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L) - .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) - // Tag entries - .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L) - .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L) - // Irrelevant entries - .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L) - // Underlying Iface entries - .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L) - .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) - .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */, - 299L /* smaller than sum(tun0) */, 0L) - .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); - - delta.migrateTun(tunUid, tunIface, new String[] {underlyingIface}); + .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L) + .addEntry(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) + .addEntry(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L) + .addEntry(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L) + // VPN package also uses some traffic through unprotected network. + .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L) + .addEntry(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) + // Tag entries + .addEntry(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L) + .addEntry(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L) + // Irrelevant entries + .addEntry(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L) + // Underlying Iface entries + .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L) + .addEntry(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) + .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */, + 299L /* smaller than sum(tun0) */, 0L) + .addEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); + + delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); assertEquals(20, delta.size()); // tunIface and TEST_IFACE entries are not changed. @@ -634,21 +634,21 @@ public class NetworkStatsTest { final String tunIface = "tun0"; final String underlyingIface = "wlan0"; NetworkStats delta = new NetworkStats(TEST_START, 9) - // 2 different apps sent/receive data via tun0. - .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L) - .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L) - // VPN package resends data through the tunnel (with exaggerated overhead) - .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L) - // 1 app already has some traffic on the underlying interface, the other doesn't yet - .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L) - // Traffic through the underlying interface via the vpn app. - // This test should redistribute this data correctly. - .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L); + // 2 different apps sent/receive data via tun0. + .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L) + .addEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L) + // VPN package resends data through the tunnel (with exaggerated overhead) + .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L) + // 1 app already has some traffic on the underlying interface, the other doesn't yet + .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L) + // Traffic through the underlying interface via the vpn app. + // This test should redistribute this data correctly. + .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L); delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); assertEquals(9, delta.size()); @@ -697,9 +697,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3); stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL); assertEquals(3, stats.size()); @@ -724,9 +724,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3); stats.filter(testUid, INTERFACES_ALL, TAG_ALL); assertEquals(2, stats.size()); @@ -755,10 +755,10 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 4) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3) - .addValues(entry4); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3) + .addEntry(entry4); stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL); assertEquals(3, stats.size()); @@ -778,8 +778,8 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(entry1) - .addValues(entry2); + .addEntry(entry1) + .addEntry(entry2); stats.filter(UID_ALL, new String[] { }, TAG_ALL); assertEquals(0, stats.size()); @@ -802,9 +802,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3); stats.filter(UID_ALL, INTERFACES_ALL, testTag); assertEquals(2, stats.size()); @@ -831,10 +831,10 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 4) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3) - .addValues(entry4); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3) + .addEntry(entry4); stats.filterDebugEntries(); @@ -891,14 +891,14 @@ public class NetworkStatsTest { 0 /* operations */); final NetworkStats statsXt = new NetworkStats(TEST_START, 3) - .addValues(appEntry) - .addValues(xtRootUidEntry) - .addValues(otherEntry); + .addEntry(appEntry) + .addEntry(xtRootUidEntry) + .addEntry(otherEntry); final NetworkStats statsEbpf = new NetworkStats(TEST_START, 3) - .addValues(appEntry) - .addValues(ebpfRootUidEntry) - .addValues(otherEntry); + .addEntry(appEntry) + .addEntry(ebpfRootUidEntry) + .addEntry(otherEntry); statsXt.apply464xlatAdjustments(stackedIface, false); statsEbpf.apply464xlatAdjustments(stackedIface, true); @@ -945,8 +945,8 @@ public class NetworkStatsTest { 0 /* operations */); NetworkStats stats = new NetworkStats(TEST_START, 2) - .addValues(firstEntry) - .addValues(secondEntry); + .addEntry(firstEntry) + .addEntry(secondEntry); // Empty map: no adjustment stats.apply464xlatAdjustments(new ArrayMap<>(), false); diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java index 5cb0d7e7a1a9..e632aafde70e 100644 --- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java +++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java @@ -22,8 +22,6 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import android.net.SocketKeepalive.InvalidPacketException; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java new file mode 100644 index 000000000000..47afed441ace --- /dev/null +++ b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static com.android.testutils.ParcelUtilsKt.assertParcelSane; + +import static org.junit.Assert.assertEquals; + +import android.telephony.SubscriptionManager; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit test for {@link android.net.TelephonyNetworkSpecifier}. + */ +@SmallTest +public class TelephonyNetworkSpecifierTest { + private static final int TEST_SUBID = 5; + + /** + * Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier + * without calling {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}. + */ + @Test + public void testBuilderBuildWithDefault() { + try { + new TelephonyNetworkSpecifier.Builder().build(); + } catch (IllegalArgumentException iae) { + // expected, test pass + } + } + + /** + * Validate that no exception will be thrown even if pass invalid subscription id to + * {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}. + */ + @Test + public void testBuilderBuildWithInvalidSubId() { + TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID) + .build(); + assertEquals(specifier.getSubscriptionId(), SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + + /** + * Validate the correctness of TelephonyNetworkSpecifier when provide valid subId. + */ + @Test + public void testBuilderBuildWithValidSubId() { + final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(TEST_SUBID) + .build(); + assertEquals(TEST_SUBID, specifier.getSubscriptionId()); + } + + /** + * Validate that parcel marshalling/unmarshalling works. + */ + @Test + public void testParcel() { + TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(TEST_SUBID) + .build(); + assertParcelSane(specifier, 1 /* fieldCount */); + } +} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index b2d363e27839..783f8d177f4a 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -21,6 +21,8 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; +import static android.content.pm.PackageManager.PERMISSION_DENIED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL; @@ -114,6 +116,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.Manifest; import android.annotation.NonNull; import android.app.AlarmManager; import android.app.NotificationManager; @@ -129,6 +132,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; +import android.net.CaptivePortalData; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.PacketKeepalive; @@ -165,6 +169,7 @@ import android.net.ResolverParamsParcel; import android.net.RouteInfo; import android.net.SocketKeepalive; import android.net.UidRange; +import android.net.Uri; import android.net.metrics.IpConnectivityLog; import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; @@ -243,8 +248,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -347,6 +354,8 @@ public class ConnectivityServiceTest { @Spy private Resources mResources; private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>(); + // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant + private final HashMap<String, Integer> mMockedPermissions = new HashMap<>(); MockContext(Context base, ContentProvider settingsProvider) { super(base); @@ -417,13 +426,39 @@ public class ConnectivityServiceTest { } @Override + public int checkPermission(String permission, int pid, int uid) { + final Integer granted = mMockedPermissions.get(permission); + if (granted == null) { + // All non-mocked permissions should be held by the test or unnecessary: check as + // normal to make sure the code does not rely on unexpected permissions. + return super.checkPermission(permission, pid, uid); + } + return granted; + } + + @Override public void enforceCallingOrSelfPermission(String permission, String message) { - // The mainline permission can only be held if signed with the network stack certificate - // Skip testing for this permission. - if (NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK.equals(permission)) return; - // All other permissions should be held by the test or unnecessary: check as normal to - // make sure the code does not rely on unexpected permissions. - super.enforceCallingOrSelfPermission(permission, message); + final Integer granted = mMockedPermissions.get(permission); + if (granted == null) { + super.enforceCallingOrSelfPermission(permission, message); + return; + } + + if (!granted.equals(PERMISSION_GRANTED)) { + throw new SecurityException("[Test] permission denied: " + permission); + } + } + + /** + * Mock checks for the specified permission, and have them behave as per {@code granted}. + * + * <p>Passing null reverts to default behavior, which does a real permission check on the + * test package. + * @param granted One of {@link PackageManager#PERMISSION_GRANTED} or + * {@link PackageManager#PERMISSION_DENIED}. + */ + public void setPermission(String permission, Integer granted) { + mMockedPermissions.put(permission, granted); } @Override @@ -575,7 +610,7 @@ public class ConnectivityServiceTest { } }; - assertEquals(na.netId, nmNetworkCaptor.getValue().netId); + assertEquals(na.network.netId, nmNetworkCaptor.getValue().netId); mNmCallbacks = nmCbCaptor.getValue(); mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor); @@ -1750,6 +1785,66 @@ public class ConnectivityServiceTest { assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); } + private void doNetworkCallbacksSanitizationTest(boolean sanitized) throws Exception { + final TestNetworkCallback callback = new TestNetworkCallback(); + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + final NetworkRequest wifiRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI).build(); + mCm.registerNetworkCallback(wifiRequest, callback); + mCm.registerDefaultNetworkCallback(defaultCallback); + + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + + final LinkProperties newLp = new LinkProperties(); + final Uri capportUrl = Uri.parse("https://capport.example.com/api"); + final CaptivePortalData capportData = new CaptivePortalData.Builder() + .setCaptive(true).build(); + newLp.setCaptivePortalApiUrl(capportUrl); + newLp.setCaptivePortalData(capportData); + mWiFiNetworkAgent.sendLinkProperties(newLp); + + final Uri expectedCapportUrl = sanitized ? null : capportUrl; + final CaptivePortalData expectedCapportData = sanitized ? null : capportData; + callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> + Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()) + && Objects.equals(expectedCapportData, lp.getCaptivePortalData())); + defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> + Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()) + && Objects.equals(expectedCapportData, lp.getCaptivePortalData())); + + final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork()); + assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl()); + assertEquals(expectedCapportData, lp.getCaptivePortalData()); + } + + @Test + public void networkCallbacksSanitizationTest_Sanitize() throws Exception { + mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + PERMISSION_DENIED); + mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, + PERMISSION_DENIED); + doNetworkCallbacksSanitizationTest(true /* sanitized */); + } + + @Test + public void networkCallbacksSanitizationTest_NoSanitize_NetworkStack() throws Exception { + mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + PERMISSION_GRANTED); + mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED); + doNetworkCallbacksSanitizationTest(false /* sanitized */); + } + + @Test + public void networkCallbacksSanitizationTest_NoSanitize_Settings() throws Exception { + mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + PERMISSION_DENIED); + mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); + doNetworkCallbacksSanitizationTest(false /* sanitized */); + } + @Test public void testMultipleLingering() throws Exception { // This test would be flaky with the default 120ms timer: that is short enough that @@ -2628,6 +2723,8 @@ public class ConnectivityServiceTest { final String testKey = "testkey"; final String testValue = "testvalue"; testBundle.putString(testKey, testValue); + mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + PERMISSION_GRANTED); mCm.startCaptivePortalApp(wifiNetwork, testBundle); final Intent signInIntent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS); assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, signInIntent.getAction()); diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 535298f9b09a..e863266c4b49 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -36,9 +36,8 @@ import android.net.IDnsResolver; import android.net.INetd; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkFactory; import android.net.NetworkInfo; -import android.net.NetworkMisc; +import android.net.NetworkProvider; import android.net.NetworkScore; import android.os.INetworkManagementService; import android.text.format.DateUtils; @@ -75,7 +74,6 @@ public class LingerMonitorTest { @Mock INetd mNetd; @Mock INetworkManagementService mNMS; @Mock Context mCtx; - @Mock NetworkMisc mMisc; @Mock NetworkNotificationManager mNotifier; @Mock Resources mResources; @@ -358,8 +356,8 @@ public class LingerMonitorTest { NetworkScore ns = new NetworkScore(); ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50); NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null, - caps, ns, mCtx, null, mMisc, mConnService, mNetd, mDnsResolver, mNMS, - NetworkFactory.SerialNumber.NONE); + caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS, + NetworkProvider.ID_NONE); nai.everValidated = true; return nai; } diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java index b783467cfaf2..de1028cd2303 100644 --- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java +++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java @@ -51,6 +51,7 @@ import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkTemplate; import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.os.Handler; import android.provider.Settings; import android.telephony.TelephonyManager; @@ -229,7 +230,7 @@ public class MultipathPolicyTrackerTest { verify(mCM).registerNetworkCallback(any(), networkCallback.capture(), any()); // Simulate callback after capability changes - final NetworkCapabilities capabilities = new NetworkCapabilities() + NetworkCapabilities capabilities = new NetworkCapabilities() .addCapability(NET_CAPABILITY_INTERNET) .addTransportType(TRANSPORT_CELLULAR) .setNetworkSpecifier(new StringNetworkSpecifier("234")); @@ -239,6 +240,19 @@ public class MultipathPolicyTrackerTest { networkCallback.getValue().onCapabilitiesChanged( TEST_NETWORK, capabilities); + + // make sure it also works with the new introduced TelephonyNetworkSpecifier + capabilities = new NetworkCapabilities() + .addCapability(NET_CAPABILITY_INTERNET) + .addTransportType(TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(234).build()); + if (!roaming) { + capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING); + } + networkCallback.getValue().onCapabilitiesChanged( + TEST_NETWORK, + capabilities); } @Test diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java index b709af1a02f1..9b248878fe96 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java @@ -33,8 +33,8 @@ import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.NetworkAgentConfig; import android.net.NetworkInfo; -import android.net.NetworkMisc; import android.os.Handler; import android.os.INetworkManagementService; import android.os.test.TestLooper; @@ -63,7 +63,6 @@ public class Nat464XlatTest { static final int NETID = 42; @Mock ConnectivityService mConnectivity; - @Mock NetworkMisc mMisc; @Mock IDnsResolver mDnsResolver; @Mock INetd mNetd; @Mock INetworkManagementService mNms; @@ -72,6 +71,7 @@ public class Nat464XlatTest { TestLooper mLooper; Handler mHandler; + NetworkAgentConfig mAgentConfig = new NetworkAgentConfig(); Nat464Xlat makeNat464Xlat() { return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) { @@ -93,7 +93,7 @@ public class Nat464XlatTest { mNai.networkInfo = new NetworkInfo(null); mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI); when(mNai.connService()).thenReturn(mConnectivity); - when(mNai.netMisc()).thenReturn(mMisc); + when(mNai.netAgentConfig()).thenReturn(mAgentConfig); when(mNai.handler()).thenReturn(mHandler); when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig); @@ -104,7 +104,7 @@ public class Nat464XlatTest { String msg = String.format("requiresClat expected %b for type=%d state=%s skip=%b " + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(), nai.networkInfo.getDetailedState(), - mMisc.skip464xlat, nai.linkProperties.getNat64Prefix(), + mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(), nai.linkProperties.getLinkAddresses()); assertEquals(msg, expected, Nat464Xlat.requiresClat(nai)); } @@ -113,7 +113,7 @@ public class Nat464XlatTest { String msg = String.format("shouldStartClat expected %b for type=%d state=%s skip=%b " + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(), nai.networkInfo.getDetailedState(), - mMisc.skip464xlat, nai.linkProperties.getNat64Prefix(), + mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(), nai.linkProperties.getLinkAddresses()); assertEquals(msg, expected, Nat464Xlat.shouldStartClat(nai)); } @@ -151,11 +151,11 @@ public class Nat464XlatTest { assertRequiresClat(true, mNai); assertShouldStartClat(true, mNai); - mMisc.skip464xlat = true; + mAgentConfig.skip464xlat = true; assertRequiresClat(false, mNai); assertShouldStartClat(false, mNai); - mMisc.skip464xlat = false; + mAgentConfig.skip464xlat = false; assertRequiresClat(true, mNai); assertShouldStartClat(true, mNai); diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java index c0f9dc14869f..f0e5774a5dea 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java @@ -326,14 +326,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -359,14 +359,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -391,14 +391,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -424,14 +424,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, + .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, + .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 4d42a612030d..a9e0b9abba9c 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -80,6 +80,7 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.ConditionVariable; import android.os.Handler; import android.os.HandlerThread; @@ -102,6 +103,7 @@ import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.TestableNetworkStatsProvider; import libcore.io.IoUtils; @@ -298,11 +300,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L)); mService.setUidForeground(UID_RED, false); mService.incrementOperationCount(UID_RED, 0xFAAD, 4); mService.setUidForeground(UID_RED, true); @@ -407,9 +409,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 10); forcePollAndWaitForIdle(); @@ -429,9 +431,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]); forcePollAndWaitForIdle(); @@ -443,10 +445,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L)); mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10); forcePollAndWaitForIdle(); @@ -480,10 +482,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) - .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) + .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xFAAD, 10); forcePollAndWaitForIdle(); @@ -501,10 +503,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) - .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) + .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); final Intent intent = new Intent(ACTION_UID_REMOVED); intent.putExtra(EXTRA_UID, UID_BLUE); mServiceContext.sendBroadcast(intent); @@ -536,8 +538,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 5); forcePollAndWaitForIdle(); @@ -552,8 +554,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]); forcePollAndWaitForIdle(); @@ -564,10 +566,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); mService.incrementOperationCount(UID_RED, 0xFAAD, 5); forcePollAndWaitForIdle(); @@ -591,9 +593,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); forcePollAndWaitForIdle(); @@ -608,9 +610,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L)); forcePollAndWaitForIdle(); // first verify entire history present @@ -654,9 +656,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3)); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL); @@ -704,11 +706,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { .thenReturn(augmentedIfaceFilter); when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL))) .thenReturn(new NetworkStats(getElapsedRealtime(), 1) - .addValues(uidStats)); + .addEntry(uidStats)); when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)) .thenReturn(new NetworkStats(getElapsedRealtime(), 2) - .addValues(tetheredStats1) - .addValues(tetheredStats2)); + .addEntry(tetheredStats1) + .addEntry(tetheredStats2)); NetworkStats stats = mService.getDetailedUidStats(ifaceFilter); @@ -745,8 +747,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); forcePollAndWaitForIdle(); @@ -760,10 +762,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L)); mService.setUidForeground(UID_RED, true); mService.incrementOperationCount(UID_RED, 0xFAAD, 1); @@ -804,9 +806,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer. // We layer them on top by inspecting the iface properties. expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); @@ -843,9 +845,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it // on top by inspecting the iface properties. expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L)); forcePollAndWaitForIdle(); @@ -885,10 +887,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // Traffic for UID_RED. final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L); // All tethering traffic, both hardware and software. final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, + .addEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L); expectNetworkStatsSummary(ifaceStats, tetherStatsHardware); @@ -1001,6 +1003,88 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { mService.unregisterUsageRequest(unknownRequest); } + @Test + public void testStatsProviderUpdateStats() throws Exception { + // Pretend that network comes online. + expectDefaultSettings(); + final NetworkState[] states = new NetworkState[]{buildWifiState(true /* isMetered */)}; + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + + // Register custom provider and retrieve callback. + final TestableNetworkStatsProvider provider = new TestableNetworkStatsProvider(); + final INetworkStatsProviderCallback cb = + mService.registerNetworkStatsProvider("TEST", provider); + assertNotNull(cb); + + mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]); + + // Verifies that one requestStatsUpdate will be called during iface update. + provider.expectStatsUpdate(0 /* unused */); + + // Create some initial traffic and report to the service. + incrementCurrentTime(HOUR_IN_MILLIS); + final NetworkStats expectedStats = new NetworkStats(0L, 1) + .addValues(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, + TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, + 128L, 2L, 128L, 2L, 1L)) + .addValues(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, + 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, + 64L, 1L, 64L, 1L, 1L)); + cb.onStatsUpdated(0 /* unused */, expectedStats, expectedStats); + + // Make another empty mutable stats object. This is necessary since the new NetworkStats + // object will be used to compare with the old one in NetworkStatsRecoder, two of them + // cannot be the same object. + expectNetworkStatsUidDetail(buildEmptyStats()); + + forcePollAndWaitForIdle(); + + // Verifies that one requestStatsUpdate and setAlert will be called during polling. + provider.expectStatsUpdate(0 /* unused */); + provider.expectSetAlert(MB_IN_BYTES); + + // Verifies that service recorded history, does not verify uid tag part. + assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1); + + // Verifies that onStatsUpdated updates the stats accordingly. + final NetworkStats stats = mSession.getSummaryForAllUid( + sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); + assertEquals(2, stats.size()); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, + DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L); + + // Verifies that unregister the callback will remove the provider from service. + cb.unregister(); + forcePollAndWaitForIdle(); + provider.assertNoCallback(); + } + + @Test + public void testStatsProviderSetAlert() throws Exception { + // Pretend that network comes online. + expectDefaultSettings(); + NetworkState[] states = new NetworkState[]{buildWifiState(true /* isMetered */)}; + mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]); + + // Register custom provider and retrieve callback. + final TestableNetworkStatsProvider provider = new TestableNetworkStatsProvider(); + final INetworkStatsProviderCallback cb = + mService.registerNetworkStatsProvider("TEST", provider); + assertNotNull(cb); + + // Simulates alert quota of the provider has been reached. + cb.onAlertReached(); + HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT); + + // Verifies that polling is triggered by alert reached. + provider.expectStatsUpdate(0 /* unused */); + // Verifies that global alert will be re-armed. + provider.expectSetAlert(MB_IN_BYTES); + } + private static File getBaseDir(File statsDir) { File baseDir = new File(statsDir, "netstats"); baseDir.mkdirs(); @@ -1102,6 +1186,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { private void expectSettings(long persistBytes, long bucketDuration, long deleteAge) throws Exception { when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS); + when(mSettings.getPollDelay()).thenReturn(0L); when(mSettings.getSampleEnabled()).thenReturn(true); final Config config = new Config(bucketDuration, deleteAge, deleteAge); diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 45cea8190844..40eae545c06b 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -1643,8 +1643,14 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* out_resource) { out_resource->name.type = ResourceType::kStyleable; - // Declare-styleable is kPrivate by default, because it technically only exists in R.java. - out_resource->visibility_level = Visibility::Level::kPublic; + if (!options_.preserve_visibility_of_styleables) { + // This was added in change Idd21b5de4d20be06c6f8c8eb5a22ccd68afc4927 to mimic aapt1, but no one + // knows exactly what for. + // + // FWIW, styleables only appear in generated R classes. For custom views these should always be + // package-private (to be used only by the view class); themes are a different story. + out_resource->visibility_level = Visibility::Level::kPublic; + } // Declare-styleable only ends up in default config; if (out_resource->config != ConfigDescription::DefaultConfig()) { diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 06bb0c9cf264..9d3ecc866c5d 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -46,6 +46,12 @@ struct ResourceParserOptions { */ bool error_on_positional_arguments = true; + /** + * If true, apply the same visibility rules for styleables as are used for + * all other resources. Otherwise, all styleables will be made public. + */ + bool preserve_visibility_of_styleables = false; + // If visibility was forced, we need to use it when creating a new resource and also error if we // try to parse the <public>, <public-group>, <java-symbol> or <symbol> tags. Maybe<Visibility::Level> visibility; diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 464225fefb85..46ad7cbe49e9 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -611,6 +611,32 @@ TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) { EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz")))); } +TEST_F(ResourceParserTest, ParseDeclareStyleablePreservingVisibility) { + StringInputStream input(R"( + <resources> + <declare-styleable name="foo"> + <attr name="myattr" /> + </declare-styleable> + <declare-styleable name="bar"> + <attr name="myattr" /> + </declare-styleable> + <public type="styleable" name="bar" /> + </resources>)"); + ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, + ConfigDescription::DefaultConfig(), + ResourceParserOptions{.preserve_visibility_of_styleables = true}); + + xml::XmlPullParser xml_parser(&input); + ASSERT_TRUE(parser.Parse(&xml_parser)); + + EXPECT_EQ( + table_.FindResource(test::ParseNameOrDie("styleable/foo")).value().entry->visibility.level, + Visibility::Level::kUndefined); + EXPECT_EQ( + table_.FindResource(test::ParseNameOrDie("styleable/bar")).value().entry->visibility.level, + Visibility::Level::kPublic); +} + TEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) { std::string input = R"( <declare-styleable xmlns:privAndroid="http://schemas.android.com/apk/prv/res/android" diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 9b81369fa9f0..21719705838d 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -159,6 +159,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options, ResourceParserOptions parser_options; parser_options.error_on_positional_arguments = !options.legacy_mode; + parser_options.preserve_visibility_of_styleables = options.preserve_visibility_of_styleables; parser_options.translatable = translatable_file; // If visibility was forced, we need to use it when creating a new resource and also error if diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h index d3456b25da9a..1752a1adac24 100644 --- a/tools/aapt2/cmd/Compile.h +++ b/tools/aapt2/cmd/Compile.h @@ -35,6 +35,8 @@ struct CompileOptions { bool pseudolocalize = false; bool no_png_crunch = false; bool legacy_mode = false; + // See comments on aapt::ResourceParserOptions. + bool preserve_visibility_of_styleables = false; bool verbose = false; }; @@ -56,6 +58,11 @@ class CompileCommand : public Command { AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch); AddOptionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings", &options_.legacy_mode); + AddOptionalSwitch("--preserve-visibility-of-styleables", + "If specified, apply the same visibility rules for\n" + "styleables as are used for all other resources.\n" + "Otherwise, all stylesables will be made public.", + &options_.preserve_visibility_of_styleables); AddOptionalFlag("--visibility", "Sets the visibility of the compiled resources to the specified\n" "level. Accepted levels: public, private, default", &visibility_); diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py index 46105f4d66b0..0b2077d9bba0 100755 --- a/tools/hiddenapi/generate_hiddenapi_lists.py +++ b/tools/hiddenapi/generate_hiddenapi_lists.py @@ -149,7 +149,12 @@ def extract_package(signature): The package name of the class containing the field/method. """ full_class_name = signature.split(";->")[0] - package_name = full_class_name[1:full_class_name.rindex("/")] + # Example: Landroid/hardware/radio/V1_2/IRadio$Proxy + if (full_class_name[0] != "L"): + raise ValueError("Expected to start with 'L': %s" % full_class_name) + full_class_name = full_class_name[1:] + # If full_class_name doesn't contain '/', then package_name will be ''. + package_name = full_class_name.rpartition("/")[0] return package_name.replace('/', '.') class FlagsDict: diff --git a/tools/lock_agent/Android.bp b/tools/lock_agent/Android.bp index 79dce4a8ce09..7b2ca9a65242 100644 --- a/tools/lock_agent/Android.bp +++ b/tools/lock_agent/Android.bp @@ -25,6 +25,7 @@ cc_binary_host { srcs: ["agent.cpp"], static_libs: [ "libbase", + "liblog", "libz", "slicer", ], diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp index c08f9b04f0df..d3958a65c704 100644 --- a/tools/stats_log_api_gen/Android.bp +++ b/tools/stats_log_api_gen/Android.bp @@ -21,9 +21,16 @@ cc_binary_host { name: "stats-log-api-gen", srcs: [ "Collation.cpp", + "atoms_info_writer.cpp", + "java_writer.cpp", + "java_writer_q.cpp", "main.cpp", + "native_writer.cpp", + "native_writer_q.cpp", + "utils.cpp", ], cflags: [ + "-DSTATS_SCHEMA_LEGACY", "-Wall", "-Werror", ], @@ -98,28 +105,23 @@ genrule { cc_library { name: "libstatslog", host_supported: true, - generated_sources: ["statslog.cpp"], - generated_headers: ["statslog.h"], + generated_sources: [ + "statslog.cpp", + ], + generated_headers: [ + "statslog.h" + ], cflags: [ "-Wall", "-Werror", ], - export_generated_headers: ["statslog.h"], + export_generated_headers: [ + "statslog.h" + ], shared_libs: [ "liblog", "libcutils", ], static_libs: ["libstatssocket"], - target: { - android: { - shared_libs: [ - "libutils", - ], - }, - host: { - static_libs: [ - "libutils", - ], - }, - }, } + diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index 373adca994a1..fa556010646c 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -379,6 +379,7 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) { int errorCount = 0; const bool dbg = false; + int maxPushedAtomId = 2; for (int i = 0; i < descriptor->field_count(); i++) { const FieldDescriptor *atomField = descriptor->field(i); @@ -447,8 +448,14 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) { } atoms->non_chained_decls.insert(nonChainedAtomDecl); } + + if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) { + maxPushedAtomId = atomDecl.code; + } } + atoms->maxPushedAtomId = maxPushedAtomId; + if (dbg) { printf("signatures = [\n"); for (map<vector<java_type_t>, set<string>>::const_iterator it = diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index 44746c96df1b..3efdd520d7f5 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -111,6 +111,7 @@ struct Atoms { set<AtomDecl> decls; set<AtomDecl> non_chained_decls; map<vector<java_type_t>, set<string>> non_chained_signatures_to_modules; + int maxPushedAtomId; }; /** @@ -123,4 +124,4 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, vector<java_type_t> } // namespace android -#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
\ No newline at end of file +#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp new file mode 100644 index 000000000000..54a9982bb5c2 --- /dev/null +++ b/tools/stats_log_api_gen/atoms_info_writer.cpp @@ -0,0 +1,227 @@ +/* + * 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 "atoms_info_writer.h" +#include "utils.h" + +#include <map> +#include <set> +#include <vector> + +namespace android { +namespace stats_log_api_gen { + +static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) { + fprintf(out, "struct StateAtomFieldOptions {\n"); + fprintf(out, " std::vector<int> primaryFields;\n"); + fprintf(out, " int exclusiveField;\n"); + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, "struct AtomsInfo {\n"); + fprintf(out, + " const static std::set<int> " + "kTruncatingTimestampAtomBlackList;\n"); + fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n"); + fprintf(out, + " const static std::set<int> kAtomsWithAttributionChain;\n"); + fprintf(out, + " const static std::map<int, StateAtomFieldOptions> " + "kStateAtomsFieldOptions;\n"); + fprintf(out, + " const static std::map<int, std::vector<int>> " + "kBytesFieldAtoms;\n"); + fprintf(out, + " const static std::set<int> kWhitelistedAtoms;\n"); + fprintf(out, "};\n"); + fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", atoms.maxPushedAtomId); + +} + +static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) { + std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed", + "audio_state_changed", + "call_state_changed", + "phone_signal_strength_changed", + "mobile_bytes_transfer_by_fg_bg", + "mobile_bytes_transfer"}; + fprintf(out, + "const std::set<int> " + "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n"); + for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin(); + blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) { + fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str()); + } + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, + "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + for (vector<AtomField>::const_iterator field = atom->fields.begin(); + field != atom->fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { + string constant = make_constant_name(atom->name); + fprintf(out, " %s,\n", constant.c_str()); + break; + } + } + } + + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, + "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->whitelisted) { + string constant = make_constant_name(atom->name); + fprintf(out, " %s,\n", constant.c_str()); + } + } + + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, "static std::map<int, int> getAtomUidField() {\n"); + fprintf(out, " std::map<int, int> uidField;\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->uidField == 0) { + continue; + } + fprintf(out, + "\n // Adding uid field for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n", + make_constant_name(atom->name).c_str(), atom->uidField); + } + + fprintf(out, " return uidField;\n"); + fprintf(out, "};\n"); + + fprintf(out, + "const std::map<int, int> AtomsInfo::kAtomsWithUidField = " + "getAtomUidField();\n"); + + fprintf(out, + "static std::map<int, StateAtomFieldOptions> " + "getStateAtomFieldOptions() {\n"); + fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n"); + fprintf(out, " StateAtomFieldOptions opt;\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) { + continue; + } + fprintf(out, + "\n // Adding primary and exclusive fields for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + fprintf(out, " opt.primaryFields.clear();\n"); + for (const auto& field : atom->primaryFields) { + fprintf(out, " opt.primaryFields.push_back(%d);\n", field); + } + + fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField); + fprintf(out, " options[static_cast<int>(%s)] = opt;\n", + make_constant_name(atom->name).c_str()); + } + + fprintf(out, " return options;\n"); + fprintf(out, "}\n"); + + fprintf(out, + "const std::map<int, StateAtomFieldOptions> " + "AtomsInfo::kStateAtomsFieldOptions = " + "getStateAtomFieldOptions();\n"); + + fprintf(out, + "static std::map<int, std::vector<int>> " + "getBinaryFieldAtoms() {\n"); + fprintf(out, " std::map<int, std::vector<int>> options;\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->binaryFields.size() == 0) { + continue; + } + fprintf(out, + "\n // Adding binary fields for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + + for (const auto& field : atom->binaryFields) { + fprintf(out, " options[static_cast<int>(%s)].push_back(%d);\n", + make_constant_name(atom->name).c_str(), field); + } + } + + fprintf(out, " return options;\n"); + fprintf(out, "}\n"); + + fprintf(out, + "const std::map<int, std::vector<int>> " + "AtomsInfo::kBytesFieldAtoms = " + "getBinaryFieldAtoms();\n"); + +} + +int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespaceStr) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "#pragma once\n"); + fprintf(out, "\n"); + fprintf(out, "#include <vector>\n"); + fprintf(out, "#include <map>\n"); + fprintf(out, "#include <set>\n"); + fprintf(out, "\n"); + + write_namespace(out, namespaceStr); + + write_atoms_info_header_body(out, atoms); + + fprintf(out, "\n"); + write_closing_namespace(out, namespaceStr); + + return 0; +} + +int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr, + const string& importHeader, const string& statslogHeader) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "#include <%s>\n", importHeader.c_str()); + fprintf(out, "#include <%s>\n", statslogHeader.c_str()); + fprintf(out, "\n"); + + write_namespace(out, namespaceStr); + + write_atoms_info_cpp_body(out, atoms); + + // Print footer + fprintf(out, "\n"); + write_closing_namespace(out, namespaceStr); + + return 0; +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h new file mode 100644 index 000000000000..12ac862871ef --- /dev/null +++ b/tools/stats_log_api_gen/atoms_info_writer.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr, + const string& importHeader, const string& statslogHeader); + +int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr); + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp new file mode 100644 index 000000000000..fef490c7e5f9 --- /dev/null +++ b/tools/stats_log_api_gen/java_writer.cpp @@ -0,0 +1,298 @@ +/* + * 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 "java_writer.h" +#include "java_writer_q.h" +#include "utils.h" + +namespace android { +namespace stats_log_api_gen { + +static int write_java_q_logger_class( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, + const string& moduleName + ) { + fprintf(out, "\n"); + fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n"); + fprintf(out, " private static class QLogger {\n"); + + write_java_q_logging_constants(out, " "); + + // Print Q write methods. + fprintf(out, "\n"); + fprintf(out, " // Write methods.\n"); + write_java_methods_q_schema( + out, signatures_to_modules, attributionDecl, moduleName, " "); + + fprintf(out, " }\n"); + return 0; +} + + +static int write_java_methods( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, + const string& moduleName, + const bool supportQ + ) { + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + // Skip if this signature is not needed for the module. + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + + // Print method signature. + if (DEFAULT_MODULE_NAME == moduleName) { + fprintf(out, " /** @hide */\n"); + } + fprintf(out, " public static void write(int code"); + vector<java_type_t> signature = signature_to_modules_it->first; + int argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (auto chainField : attributionDecl.fields) { + fprintf(out, ", %s[] %s", + java_type_name(chainField.javaType), chainField.name.c_str()); + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", SparseArray<Object> valueMap"); + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ") {\n"); + + // Print method body. + string indent(""); + if (supportQ) { + // TODO(b/146235828): Use just SDK_INT check once it is incremented from Q. + fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q ||\n"); + fprintf(out, " Build.VERSION.CODENAME.equals(\"R\")) {\n"); + indent = " "; + } + + // Start StatsEvent.Builder. + fprintf(out, "%s final StatsEvent.Builder builder = StatsEvent.newBuilder();\n", + indent.c_str()); + + // Write atom code. + fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str()); + + // Write the args. + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_BOOLEAN: + fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_INT: + case JAVA_TYPE_ENUM: + fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_FLOAT: + fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_LONG: + fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_STRING: + fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_BYTE_ARRAY: + fprintf(out, "%s builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n", + indent.c_str(), argIndex, argIndex); + break; + case JAVA_TYPE_ATTRIBUTION_CHAIN: + { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + + fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str()); + fprintf(out, "%s null == %s ? new int[0] : %s,\n", + indent.c_str(), uidName, uidName); + fprintf(out, "%s null == %s ? new String[0] : %s);\n", + indent.c_str(), tagName, tagName); + break; + } + case JAVA_TYPE_KEY_VALUE_PAIR: + fprintf(out, "\n"); + fprintf(out, + "%s // Write KeyValuePairs.\n", indent.c_str()); + fprintf(out, + "%s final int count = valueMap.size();\n", indent.c_str()); + fprintf(out, + "%s final SparseIntArray intMap = new SparseIntArray();\n", + indent.c_str()); + fprintf(out, + "%s final SparseLongArray longMap = new SparseLongArray();\n", + indent.c_str()); + fprintf(out, + "%s final SparseArray<String> stringMap = new SparseArray<>();\n", + indent.c_str()); + fprintf(out, + "%s final SparseArray<Float> floatMap = new SparseArray<>();\n", + indent.c_str()); + fprintf(out, + "%s for (int i = 0; i < count; i++) {\n", indent.c_str()); + fprintf(out, + "%s final int key = valueMap.keyAt(i);\n", indent.c_str()); + fprintf(out, + "%s final Object value = valueMap.valueAt(i);\n", + indent.c_str()); + fprintf(out, + "%s if (value instanceof Integer) {\n", indent.c_str()); + fprintf(out, + "%s intMap.put(key, (Integer) value);\n", indent.c_str()); + fprintf(out, + "%s } else if (value instanceof Long) {\n", indent.c_str()); + fprintf(out, + "%s longMap.put(key, (Long) value);\n", indent.c_str()); + fprintf(out, + "%s } else if (value instanceof String) {\n", indent.c_str()); + fprintf(out, + "%s stringMap.put(key, (String) value);\n", indent.c_str()); + fprintf(out, + "%s } else if (value instanceof Float) {\n", indent.c_str()); + fprintf(out, + "%s floatMap.put(key, (Float) value);\n", indent.c_str()); + fprintf(out, + "%s }\n", indent.c_str()); + fprintf(out, + "%s }\n", indent.c_str()); + fprintf(out, + "%s builder.writeKeyValuePairs(" + "intMap, longMap, stringMap, floatMap);\n", indent.c_str()); + break; + default: + // Unsupported types: OBJECT, DOUBLE. + fprintf(stderr, "Encountered unsupported type."); + return 1; + } + argIndex++; + } + + fprintf(out, "\n"); + fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str()); + fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str()); + + // Add support for writing using Q schema if this is not the default module. + if (supportQ) { + fprintf(out, " } else {\n"); + fprintf(out, " QLogger.write(code"); + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + fprintf(out, ", %s, %s", uidName, tagName); + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + // Module logging does not yet support key value pair. + fprintf(stderr, "Module logging does not yet support key value pair.\n"); + return 1; + } else { + fprintf(out, ", arg%d", argIndex); + } + argIndex++; + } + fprintf(out, ");\n"); + fprintf(out, " }\n"); // if + } + + fprintf(out, " }\n"); // method + fprintf(out, "\n"); + } + return 0; + +} + +int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& javaClass, + const string& javaPackage, const bool supportQ) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "package %s;\n", javaPackage.c_str()); + fprintf(out, "\n"); + fprintf(out, "\n"); + if (supportQ) { + fprintf(out, "import android.os.Build;\n"); + fprintf(out, "import android.os.SystemClock;\n"); + } + + if (DEFAULT_MODULE_NAME == moduleName) { + // Mainline modules don't use WorkSource logging. + fprintf(out, "import android.os.WorkSource;\n"); + + // SparseArray is used for writing KeyValuePairs; not supported for Mainline modules. + fprintf(out, "import android.util.SparseArray;\n"); + fprintf(out, "import android.util.SparseIntArray;\n"); + fprintf(out, "import android.util.SparseLongArray;\n"); + } + + fprintf(out, "import android.util.StatsEvent;\n"); + fprintf(out, "import android.util.StatsLog;\n"); + + if (DEFAULT_MODULE_NAME == moduleName) { + // List is used for WorkSource writing. Only needed for default module. + fprintf(out, "\n"); + fprintf(out, "import java.util.ArrayList;\n"); + } + + fprintf(out, "\n"); + fprintf(out, "\n"); + fprintf(out, "/**\n"); + fprintf(out, " * Utility class for logging statistics events.\n"); + if (DEFAULT_MODULE_NAME == moduleName) { + fprintf(out, " * @hide\n"); + } + fprintf(out, " */\n"); + fprintf(out, "public class %s {\n", javaClass.c_str()); + + write_java_atom_codes(out, atoms, moduleName); + write_java_enum_values(out, atoms, moduleName); + + int errors = 0; + + // Print write methods. + fprintf(out, " // Write methods\n"); + errors += write_java_methods( + out, atoms.signatures_to_modules, attributionDecl, moduleName, supportQ); + errors += write_java_non_chained_methods( + out, atoms.non_chained_signatures_to_modules, moduleName); + if (DEFAULT_MODULE_NAME == moduleName) { + errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName); + } + + if (supportQ) { + errors += write_java_q_logger_class( + out, atoms.signatures_to_modules, attributionDecl, moduleName); + } + + fprintf(out, "}\n"); + + return errors; +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h new file mode 100644 index 000000000000..9324b23e4025 --- /dev/null +++ b/tools/stats_log_api_gen/java_writer.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <map> +#include <set> +#include <vector> + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& javaClass, + const string& javaPackage, const bool supportQ); + +} // namespace stats_log_api_gen +} // namespace android + diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp new file mode 100644 index 000000000000..d6899f6131c6 --- /dev/null +++ b/tools/stats_log_api_gen/java_writer_q.cpp @@ -0,0 +1,470 @@ +/* + * 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 "java_writer_q.h" +#include "utils.h" + +namespace android { +namespace stats_log_api_gen { + +void write_java_q_logging_constants(FILE* out, const string& indent) { + fprintf(out, "%s// Payload limits.\n", indent.c_str()); + fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str()); + fprintf(out, + "%sprivate static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n", + indent.c_str()); + + // Value types. Must match with EventLog.java and log.h. + fprintf(out, "\n"); + fprintf(out, "%s// Value types.\n", indent.c_str()); + fprintf(out, "%sprivate static final byte INT_TYPE = 0;\n", indent.c_str()); + fprintf(out, "%sprivate static final byte LONG_TYPE = 1;\n", indent.c_str()); + fprintf(out, "%sprivate static final byte STRING_TYPE = 2;\n", indent.c_str()); + fprintf(out, "%sprivate static final byte LIST_TYPE = 3;\n", indent.c_str()); + fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str()); + + // Size of each value type. + // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value. + fprintf(out, "\n"); + fprintf(out, "%s// Size of each value type.\n", indent.c_str()); + fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str()); + fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str()); + // Longs take 9 bytes, 1 for the type and 8 for the value. + fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str()); + // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length. + fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str()); + fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str()); +} + +int write_java_methods_q_schema( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, + const string& moduleName, + const string& indent) { + int requiredHelpers = 0; + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + // Skip if this signature is not needed for the module. + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + + // Print method signature. + vector<java_type_t> signature = signature_to_modules_it->first; + fprintf(out, "%spublic static void write(int code", indent.c_str()); + int argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (auto chainField : attributionDecl.fields) { + fprintf(out, ", %s[] %s", + java_type_name(chainField.javaType), chainField.name.c_str()); + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + // Module logging does not yet support key value pair. + fprintf(stderr, "Module logging does not yet support key value pair.\n"); + continue; + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ") {\n"); + + // Calculate the size of the buffer. + fprintf(out, "%s // Initial overhead of the list, timestamp, and atom tag.\n", + indent.c_str()); + fprintf(out, + "%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n", + indent.c_str()); + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_BOOLEAN: + case JAVA_TYPE_INT: + case JAVA_TYPE_FLOAT: + case JAVA_TYPE_ENUM: + fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_LONG: + // Longs take 9 bytes, 1 for the type and 8 for the value. + fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_STRING: + // Strings take 5 metadata bytes + length of byte encoded string. + fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex); + fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, + "%s byte[] arg%dBytes = " + "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", + indent.c_str(), argIndex, argIndex); + fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", + indent.c_str(), argIndex); + break; + case JAVA_TYPE_BYTE_ARRAY: + // Byte arrays take 5 metadata bytes + length of byte array. + fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex); + fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", + indent.c_str(), argIndex); + break; + case JAVA_TYPE_ATTRIBUTION_CHAIN: + { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + // Null checks on the params. + fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName); + fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName, + java_type_name(attributionDecl.fields.front().javaType)); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName); + fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName, + java_type_name(attributionDecl.fields.back().javaType)); + fprintf(out, "%s }\n", indent.c_str()); + + // First check that the lengths of the uid and tag arrays are the same. + fprintf(out, "%s if (%s.length != %s.length) {\n", + indent.c_str(), uidName, tagName); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str()); + fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", + indent.c_str(), tagName); + fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n", + indent.c_str(), argIndex, tagName, tagName); + fprintf(out, + "%s int str%dlen = " + "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n", + indent.c_str(), argIndex, argIndex); + fprintf(out, + "%s attrSize += " + "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n", + indent.c_str(), argIndex); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s needed += attrSize;\n", indent.c_str()); + break; + } + default: + // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR. + fprintf(stderr, "Module logging does not yet support key value pair.\n"); + return 1; + } + argIndex++; + } + + // Now we have the size that is needed. Check for overflow and return if needed. + fprintf(out, "%s if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str()); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s }\n", indent.c_str()); + + // Create new buffer, and associated data types. + fprintf(out, "%s byte[] buff = new byte[needed];\n", indent.c_str()); + fprintf(out, "%s int pos = 0;\n", indent.c_str()); + + // Initialize the buffer with list data type. + fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = %zu;\n", indent.c_str(), signature.size() + 2); + fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); + + // Write timestamp. + fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n", indent.c_str()); + fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str()); + fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); + + // Write atom code. + fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, code);\n", indent.c_str()); + fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); + + // Write the args. + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_BOOLEAN: + fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n", + indent.c_str(), argIndex); + fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_INT: + case JAVA_TYPE_ENUM: + fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); + fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_FLOAT: + requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT; + fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); + fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_LONG: + fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); + fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_STRING: + fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n", + indent.c_str(), argIndex); + fprintf(out, "%s System.arraycopy(" + "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n", + indent.c_str(), argIndex, argIndex); + fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", + indent.c_str(), argIndex); + break; + case JAVA_TYPE_BYTE_ARRAY: + fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n", + indent.c_str(), argIndex); + fprintf(out, "%s System.arraycopy(" + "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n", + indent.c_str(), argIndex, argIndex); + fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", + indent.c_str(), argIndex); + break; + case JAVA_TYPE_ATTRIBUTION_CHAIN: + { + requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION; + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + + fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n", indent.c_str(), + uidName, tagName); + fprintf(out, "%s pos += attrSize;\n", indent.c_str()); + break; + } + default: + // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR. + fprintf(stderr, + "Object, Double, and KeyValuePairs are not supported in module logging"); + return 1; + } + argIndex++; + } + + fprintf(out, "%s StatsLog.writeRaw(buff, pos);\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + } + + write_java_helpers_for_q_schema_methods(out, attributionDecl, requiredHelpers, indent); + + return 0; +} + +void write_java_helpers_for_q_schema_methods( + FILE* out, + const AtomDecl &attributionDecl, + const int requiredHelpers, + const string& indent) { + fprintf(out, "\n"); + fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str()); + fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n", + indent.c_str()); + fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str()); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + + fprintf(out, "%sprivate static void copyLong(byte[] buff, int pos, long val) {\n", + indent.c_str()); + fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 4] = (byte) (val >> 32);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 5] = (byte) (val >> 40);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 6] = (byte) (val >> 48);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 7] = (byte) (val >> 56);\n", indent.c_str()); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + + if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) { + fprintf(out, "%sprivate static void copyFloat(byte[] buff, int pos, float val) {\n", + indent.c_str()); + fprintf(out, "%s copyInt(buff, pos, Float.floatToIntBits(val));\n", indent.c_str()); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + } + + if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) { + fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos", + indent.c_str()); + for (auto chainField : attributionDecl.fields) { + fprintf(out, ", %s[] %s", + java_type_name(chainField.javaType), chainField.name.c_str()); + } + fprintf(out, ") {\n"); + + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + + // Write the first list begin. + fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = (byte) (%s.length);\n", indent.c_str(), tagName); + fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); + + // Iterate through the attribution chain and write the nodes. + fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName); + // Write the list begin. + fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = %lu;\n", + indent.c_str(), attributionDecl.fields.size()); + fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); + + // Write the uid. + fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, %s[i]);\n", indent.c_str(), uidName); + fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); + + // Write the tag. + fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", + indent.c_str(), tagName, tagName, tagName); + fprintf(out, "%s byte[] %sByte = " + "%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", + indent.c_str(), tagName, tagName); + fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName); + fprintf(out, "%s System.arraycopy(" + "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n", + indent.c_str(), tagName, tagName); + fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", + indent.c_str(), tagName); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + } +} + +#if defined(STATS_SCHEMA_LEGACY) +static void write_java_method( + FILE* out, + const string& method_name, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl) { + + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector<java_type_t> signature = signature_to_modules_it->first; + fprintf(out, " /** @hide */\n"); + fprintf(out, " public static native int %s(int code", method_name.c_str()); + int argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (auto chainField : attributionDecl.fields) { + fprintf(out, ", %s[] %s", + java_type_name(chainField.javaType), chainField.name.c_str()); + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", SparseArray<Object> value_map"); + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ");\n"); + fprintf(out, "\n"); + } +} + +int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "package android.util;\n"); + fprintf(out, "\n"); + fprintf(out, "import android.os.WorkSource;\n"); + fprintf(out, "import android.util.SparseArray;\n"); + fprintf(out, "import java.util.ArrayList;\n"); + fprintf(out, "\n"); + fprintf(out, "\n"); + fprintf(out, "/**\n"); + fprintf(out, " * API For logging statistics events.\n"); + fprintf(out, " * @hide\n"); + fprintf(out, " */\n"); + fprintf(out, "public class StatsLogInternal {\n"); + write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME); + + write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME); + + // Print write methods + fprintf(out, " // Write methods\n"); + write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl); + write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules, + attributionDecl); + write_java_work_source_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME); + + fprintf(out, "}\n"); + + return 0; +} + +int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& javaClass, + const string& javaPackage) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "package %s;\n", javaPackage.c_str()); + fprintf(out, "\n"); + fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n"); + fprintf(out, "\n"); + fprintf(out, "import android.util.StatsLog;\n"); + fprintf(out, "import android.os.SystemClock;\n"); + fprintf(out, "\n"); + fprintf(out, "import java.util.ArrayList;\n"); + fprintf(out, "\n"); + fprintf(out, "\n"); + fprintf(out, "/**\n"); + fprintf(out, " * Utility class for logging statistics events.\n"); + fprintf(out, " */\n"); + fprintf(out, "public class %s {\n", javaClass.c_str()); + + write_java_q_logging_constants(out, " "); + + write_java_atom_codes(out, atoms, moduleName); + + write_java_enum_values(out, atoms, moduleName); + + int errors = 0; + // Print write methods + fprintf(out, " // Write methods\n"); + errors += write_java_methods_q_schema(out, atoms.signatures_to_modules, attributionDecl, + moduleName, " "); + errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules, + moduleName); + + fprintf(out, "}\n"); + + return errors; +} +#endif + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h new file mode 100644 index 000000000000..96ac745beef8 --- /dev/null +++ b/tools/stats_log_api_gen/java_writer_q.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <map> +#include <set> +#include <vector> + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +void write_java_q_logging_constants(FILE* out, const string& indent); + +int write_java_methods_q_schema( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, + const string& moduleName, + const string& indent); + +void write_java_helpers_for_q_schema_methods( + FILE * out, + const AtomDecl &attributionDecl, + const int requiredHelpers, + const string& indent); + +#if defined(STATS_SCHEMA_LEGACY) +int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl); + +int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, + const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass, + const string& javaPackage); +#endif +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index f62fef076f48..00a370484823 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -1,9 +1,17 @@ #include "Collation.h" +#include "atoms_info_writer.h" +#if !defined(STATS_SCHEMA_LEGACY) +#include "java_writer.h" +#endif +#include "java_writer_q.h" +#include "native_writer.h" +#include "utils.h" #include "frameworks/base/cmds/statsd/src/atoms.pb.h" +#include <map> #include <set> #include <vector> @@ -12,1490 +20,19 @@ #include <stdlib.h> #include <string.h> -#include "android-base/strings.h" - using namespace google::protobuf; using namespace std; namespace android { namespace stats_log_api_gen { -int maxPushedAtomId = 2; - -const string DEFAULT_MODULE_NAME = "DEFAULT"; -const string DEFAULT_CPP_NAMESPACE = "android,util"; -const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h"; -const string DEFAULT_JAVA_PACKAGE = "android.util"; -const string DEFAULT_JAVA_CLASS = "StatsLogInternal"; - -const int JAVA_MODULE_REQUIRES_FLOAT = 0x01; -const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02; - using android::os::statsd::Atom; -/** - * Turn lower and camel case into upper case with underscores. - */ -static string -make_constant_name(const string& str) -{ - string result; - const int N = str.size(); - bool underscore_next = false; - for (int i=0; i<N; i++) { - char c = str[i]; - if (c >= 'A' && c <= 'Z') { - if (underscore_next) { - result += '_'; - underscore_next = false; - } - } else if (c >= 'a' && c <= 'z') { - c = 'A' + c - 'a'; - underscore_next = true; - } else if (c == '_') { - underscore_next = false; - } - result += c; - } - return result; -} - -static const char* -cpp_type_name(java_type_t type) -{ - switch (type) { - case JAVA_TYPE_BOOLEAN: - return "bool"; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - return "int32_t"; - case JAVA_TYPE_LONG: - return "int64_t"; - case JAVA_TYPE_FLOAT: - return "float"; - case JAVA_TYPE_DOUBLE: - return "double"; - case JAVA_TYPE_STRING: - return "char const*"; - case JAVA_TYPE_BYTE_ARRAY: - return "const BytesField&"; - default: - return "UNKNOWN"; - } -} - -static const char* -java_type_name(java_type_t type) -{ - switch (type) { - case JAVA_TYPE_BOOLEAN: - return "boolean"; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - return "int"; - case JAVA_TYPE_LONG: - return "long"; - case JAVA_TYPE_FLOAT: - return "float"; - case JAVA_TYPE_DOUBLE: - return "double"; - case JAVA_TYPE_STRING: - return "java.lang.String"; - case JAVA_TYPE_BYTE_ARRAY: - return "byte[]"; - default: - return "UNKNOWN"; - } -} - -static bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) { - if (moduleName == DEFAULT_MODULE_NAME) { - return true; - } - return atomDecl.hasModule && (moduleName == atomDecl.moduleName); -} - -static bool signature_needed_for_module(const set<string>& modules, const string& moduleName) { - if (moduleName == DEFAULT_MODULE_NAME) { - return true; - } - return modules.find(moduleName) != modules.end(); -} - -static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) { - std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed", - "audio_state_changed", - "call_state_changed", - "phone_signal_strength_changed", - "mobile_bytes_transfer_by_fg_bg", - "mobile_bytes_transfer"}; - fprintf(out, - "const std::set<int> " - "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n"); - for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin(); - blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) { - fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str()); - } - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, - "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - for (vector<AtomField>::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - string constant = make_constant_name(atom->name); - fprintf(out, " %s,\n", constant.c_str()); - break; - } - } - } - - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, - "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->whitelisted) { - string constant = make_constant_name(atom->name); - fprintf(out, " %s,\n", constant.c_str()); - } - } - - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, "static std::map<int, int> getAtomUidField() {\n"); - fprintf(out, " std::map<int, int> uidField;\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->uidField == 0) { - continue; - } - fprintf(out, - "\n // Adding uid field for atom " - "(%d)%s\n", - atom->code, atom->name.c_str()); - fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n", - make_constant_name(atom->name).c_str(), atom->uidField); - } - - fprintf(out, " return uidField;\n"); - fprintf(out, "};\n"); - - fprintf(out, - "const std::map<int, int> AtomsInfo::kAtomsWithUidField = " - "getAtomUidField();\n"); - - fprintf(out, - "static std::map<int, StateAtomFieldOptions> " - "getStateAtomFieldOptions() {\n"); - fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n"); - fprintf(out, " StateAtomFieldOptions opt;\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) { - continue; - } - fprintf(out, - "\n // Adding primary and exclusive fields for atom " - "(%d)%s\n", - atom->code, atom->name.c_str()); - fprintf(out, " opt.primaryFields.clear();\n"); - for (const auto& field : atom->primaryFields) { - fprintf(out, " opt.primaryFields.push_back(%d);\n", field); - } - - fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField); - fprintf(out, " options[static_cast<int>(%s)] = opt;\n", - make_constant_name(atom->name).c_str()); - } - - fprintf(out, " return options;\n"); - fprintf(out, "}\n"); - - fprintf(out, - "const std::map<int, StateAtomFieldOptions> " - "AtomsInfo::kStateAtomsFieldOptions = " - "getStateAtomFieldOptions();\n"); - - fprintf(out, - "static std::map<int, std::vector<int>> " - "getBinaryFieldAtoms() {\n"); - fprintf(out, " std::map<int, std::vector<int>> options;\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->binaryFields.size() == 0) { - continue; - } - fprintf(out, - "\n // Adding binary fields for atom " - "(%d)%s\n", - atom->code, atom->name.c_str()); - - for (const auto& field : atom->binaryFields) { - fprintf(out, " options[static_cast<int>(%s)].push_back(%d);\n", - make_constant_name(atom->name).c_str(), field); - } - } - - fprintf(out, " return options;\n"); - fprintf(out, "}\n"); - - fprintf(out, - "const std::map<int, std::vector<int>> " - "AtomsInfo::kBytesFieldAtoms = " - "getBinaryFieldAtoms();\n"); -} - -// Writes namespaces for the cpp and header files, returning the number of namespaces written. -void write_namespace(FILE* out, const string& cppNamespaces) { - vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); - for (string cppNamespace : cppNamespaceVec) { - fprintf(out, "namespace %s {\n", cppNamespace.c_str()); - } -} - -// Writes namespace closing brackets for cpp and header files. -void write_closing_namespace(FILE* out, const string& cppNamespaces) { - vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); - for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) { - fprintf(out, "} // namespace %s\n", it->c_str()); - } -} - -static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, - const string& moduleName, const string& cppNamespace, - const string& importHeader) { - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - - fprintf(out, "#include <mutex>\n"); - fprintf(out, "#include <chrono>\n"); - fprintf(out, "#include <thread>\n"); - fprintf(out, "#ifdef __ANDROID__\n"); - fprintf(out, "#include <cutils/properties.h>\n"); - fprintf(out, "#endif\n"); - fprintf(out, "#include <stats_event_list.h>\n"); - fprintf(out, "#include <log/log.h>\n"); - fprintf(out, "#include <%s>\n", importHeader.c_str()); - fprintf(out, "#include <utils/SystemClock.h>\n"); - fprintf(out, "\n"); - - write_namespace(out, cppNamespace); - fprintf(out, "// the single event tag id for all stats logs\n"); - fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); - fprintf(out, "#ifdef __ANDROID__\n"); - fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n"); - fprintf(out, "#else\n"); - fprintf(out, "const static bool kStatsdEnabled = false;\n"); - fprintf(out, "#endif\n"); - - // AtomsInfo is only used by statsd internally and is not needed for other modules. - if (moduleName == DEFAULT_MODULE_NAME) { - write_atoms_info_cpp(out, atoms); - } - - fprintf(out, "int64_t lastRetryTimestampNs = -1;\n"); - fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n"); - fprintf(out, "static std::mutex mLogdRetryMutex;\n"); - - // Print write methods - fprintf(out, "\n"); - for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); - signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { - if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_to_modules_it->first; - int argIndex; - - fprintf(out, "int\n"); - fprintf(out, "try_stats_write(int32_t code"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", - cpp_type_name(chainField.javaType), - chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " - "const std::map<int, int64_t>& arg%d_2, " - "const std::map<int, char const*>& arg%d_3, " - "const std::map<int, float>& arg%d_4", - argIndex, argIndex, argIndex, argIndex); - } else { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - argIndex = 1; - fprintf(out, " if (kStatsdEnabled) {\n"); - fprintf(out, " stats_event_list event(kStatsEventTag);\n"); - fprintf(out, " event << android::elapsedRealtimeNano();\n\n"); - fprintf(out, " event << code;\n\n"); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (const auto &chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, " if (%s_length != %s.size()) {\n", - attributionDecl.fields.front().name.c_str(), chainField.name.c_str()); - fprintf(out, " return -EINVAL;\n"); - fprintf(out, " }\n"); - } - } - fprintf(out, "\n event.begin();\n"); - fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n", - attributionDecl.fields.front().name.c_str()); - fprintf(out, " event.begin();\n"); - for (const auto &chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str()); - fprintf(out, " event << %s[i];\n", chainField.name.c_str()); - fprintf(out, " } else {\n"); - fprintf(out, " event << \"\";\n"); - fprintf(out, " }\n"); - } else { - fprintf(out, " event << %s[i];\n", chainField.name.c_str()); - } - } - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - fprintf(out, " event.end();\n\n"); - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, " event.begin();\n\n"); - fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " event.end();\n\n"); - } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, - " event.AppendCharArray(arg%d.arg, " - "arg%d.arg_length);\n", - argIndex, argIndex); - } else { - if (*arg == JAVA_TYPE_STRING) { - fprintf(out, " if (arg%d == NULL) {\n", argIndex); - fprintf(out, " arg%d = \"\";\n", argIndex); - fprintf(out, " }\n"); - } - fprintf(out, " event << arg%d;\n", argIndex); - } - argIndex++; - } - - fprintf(out, " return event.write(LOG_ID_STATS);\n"); - fprintf(out, " } else {\n"); - fprintf(out, " return 1;\n"); - fprintf(out, " }\n"); - fprintf(out, "}\n"); - fprintf(out, "\n"); - } - - for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); - signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { - if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_to_modules_it->first; - int argIndex; - - fprintf(out, "int\n"); - fprintf(out, "stats_write(int32_t code"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", - cpp_type_name(chainField.javaType), - chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, - ", const std::map<int, int32_t>& arg%d_1, " - "const std::map<int, int64_t>& arg%d_2, " - "const std::map<int, char const*>& arg%d_3, " - "const std::map<int, float>& arg%d_4", - argIndex, argIndex, argIndex, argIndex); - } else { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - fprintf(out, " int ret = 0;\n"); - - fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n"); - fprintf(out, " ret = try_stats_write(code"); - - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", %s", - chainField.name.c_str()); - } else { - fprintf(out, ", %s, %s_length", - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, - argIndex, argIndex, argIndex); - } else { - fprintf(out, ", arg%d", argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, " if (ret >= 0) { break; }\n"); - - fprintf(out, " {\n"); - fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n"); - fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= " - "kMinRetryIntervalNs) break;\n"); - fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n"); - fprintf(out, " }\n"); - fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n"); - fprintf(out, " }\n"); - fprintf(out, " if (ret < 0) {\n"); - fprintf(out, " note_log_drop(ret, code);\n"); - fprintf(out, " }\n"); - fprintf(out, " return ret;\n"); - fprintf(out, "}\n"); - fprintf(out, "\n"); - } - - for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); - signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { - if (!signature_needed_for_module(signature_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_it->first; - int argIndex; - - fprintf(out, "int\n"); - fprintf(out, "try_stats_write_non_chained(int32_t code"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - argIndex = 1; - fprintf(out, " if (kStatsdEnabled) {\n"); - fprintf(out, " stats_event_list event(kStatsEventTag);\n"); - fprintf(out, " event << android::elapsedRealtimeNano();\n\n"); - fprintf(out, " event << code;\n\n"); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (argIndex == 1) { - fprintf(out, " event.begin();\n\n"); - fprintf(out, " event.begin();\n"); - } - if (*arg == JAVA_TYPE_STRING) { - fprintf(out, " if (arg%d == NULL) {\n", argIndex); - fprintf(out, " arg%d = \"\";\n", argIndex); - fprintf(out, " }\n"); - } - if (*arg == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, - " event.AppendCharArray(arg%d.arg, " - "arg%d.arg_length);", - argIndex, argIndex); - } else { - fprintf(out, " event << arg%d;\n", argIndex); - } - if (argIndex == 2) { - fprintf(out, " event.end();\n\n"); - fprintf(out, " event.end();\n\n"); - } - argIndex++; - } - - fprintf(out, " return event.write(LOG_ID_STATS);\n"); - fprintf(out, " } else {\n"); - fprintf(out, " return 1;\n"); - fprintf(out, " }\n"); - fprintf(out, "}\n"); - fprintf(out, "\n"); - } - - for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); - signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { - if (!signature_needed_for_module(signature_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_it->first; - int argIndex; - - fprintf(out, "int\n"); - fprintf(out, "stats_write_non_chained(int32_t code"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - - fprintf(out, " int ret = 0;\n"); - fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n"); - fprintf(out, " ret = try_stats_write_non_chained(code"); - - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - fprintf(out, ", arg%d", argIndex); - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, " if (ret >= 0) { break; }\n"); - - fprintf(out, " {\n"); - fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n"); - fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= " - "kMinRetryIntervalNs) break;\n"); - fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n"); - fprintf(out, " }\n"); - - fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n"); - fprintf(out, " }\n"); - fprintf(out, " if (ret < 0) {\n"); - fprintf(out, " note_log_drop(ret, code);\n"); - fprintf(out, " }\n"); - fprintf(out, " return ret;\n\n"); - fprintf(out, "}\n"); - - fprintf(out, "\n"); - } - - - // Print footer - fprintf(out, "\n"); - write_closing_namespace(out, cppNamespace); - - return 0; -} - -void build_non_chained_decl_map(const Atoms& atoms, - std::map<int, set<AtomDecl>::const_iterator>* decl_map){ - for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin(); - atom != atoms.non_chained_decls.end(); atom++) { - decl_map->insert(std::make_pair(atom->code, atom)); - } -} - -static void write_cpp_usage( - FILE* out, const string& method_name, const string& atom_code_name, - const AtomDecl& atom, const AtomDecl &attributionDecl) { - fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), - atom_code_name.c_str()); - - for (vector<AtomField>::const_iterator field = atom.fields.begin(); - field != atom.fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", - cpp_type_name(chainField.javaType), - chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int32_t>& %s_int" - ", const std::map<int, int64_t>& %s_long" - ", const std::map<int, char const*>& %s_str" - ", const std::map<int, float>& %s_float", - field->name.c_str(), - field->name.c_str(), - field->name.c_str(), - field->name.c_str()); - } else { - fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str()); - } - } - fprintf(out, ");\n"); -} - -static void write_cpp_method_header( - FILE* out, - const string& method_name, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const AtomDecl &attributionDecl, const string& moduleName) { - - for (auto signature_to_modules_it = signatures_to_modules.begin(); - signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { - // Skip if this signature is not needed for the module. - if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { - continue; - } - - vector<java_type_t> signature = signature_to_modules_it->first; - fprintf(out, "int %s(int32_t code", method_name.c_str()); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", - cpp_type_name(chainField.javaType), chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " - "const std::map<int, int64_t>& arg%d_2, " - "const std::map<int, char const*>& arg%d_3, " - "const std::map<int, float>& arg%d_4", - argIndex, argIndex, argIndex, argIndex); - } else { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - - } -} - -static int -write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, - const string& moduleName, const string& cppNamespace) -{ - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "#pragma once\n"); - fprintf(out, "\n"); - fprintf(out, "#include <stdint.h>\n"); - fprintf(out, "#include <vector>\n"); - fprintf(out, "#include <map>\n"); - fprintf(out, "#include <set>\n"); - fprintf(out, "\n"); - - write_namespace(out, cppNamespace); - fprintf(out, "\n"); - fprintf(out, "/*\n"); - fprintf(out, " * API For logging statistics events.\n"); - fprintf(out, " */\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * Constants for atom codes.\n"); - fprintf(out, " */\n"); - fprintf(out, "enum {\n"); - - std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map; - build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); - - size_t i = 0; - // Print atom constants - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - // Skip if the atom is not needed for the module. - if (!atom_needed_for_module(*atom, moduleName)) { - continue; - } - string constant = make_constant_name(atom->name); - fprintf(out, "\n"); - fprintf(out, " /**\n"); - fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str()); - write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl); - - auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); - if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { - write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second, - attributionDecl); - } - fprintf(out, " */\n"); - char const* const comma = (i == atoms.decls.size() - 1) ? "" : ","; - fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma); - if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) { - maxPushedAtomId = atom->code; - } - i++; - } - fprintf(out, "\n"); - fprintf(out, "};\n"); - fprintf(out, "\n"); - - // Print constants for the enum values. - fprintf(out, "//\n"); - fprintf(out, "// Constants for enum values\n"); - fprintf(out, "//\n\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - // Skip if the atom is not needed for the module. - if (!atom_needed_for_module(*atom, moduleName)) { - continue; - } - - for (vector<AtomField>::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ENUM) { - fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), - field->name.c_str()); - for (map<int, string>::const_iterator value = field->enumValues.begin(); - value != field->enumValues.end(); value++) { - fprintf(out, "const int32_t %s__%s__%s = %d;\n", - make_constant_name(atom->message).c_str(), - make_constant_name(field->name).c_str(), - make_constant_name(value->second).c_str(), - value->first); - } - fprintf(out, "\n"); - } - } - } - - fprintf(out, "struct BytesField {\n"); - fprintf(out, - " BytesField(char const* array, size_t len) : arg(array), " - "arg_length(len) {}\n"); - fprintf(out, " char const* arg;\n"); - fprintf(out, " size_t arg_length;\n"); - fprintf(out, "};\n"); - fprintf(out, "\n"); - - // This metadata is only used by statsd, which uses the default libstatslog. - if (moduleName == DEFAULT_MODULE_NAME) { - - fprintf(out, "struct StateAtomFieldOptions {\n"); - fprintf(out, " std::vector<int> primaryFields;\n"); - fprintf(out, " int exclusiveField;\n"); - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, "struct AtomsInfo {\n"); - fprintf(out, - " const static std::set<int> " - "kTruncatingTimestampAtomBlackList;\n"); - fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n"); - fprintf(out, - " const static std::set<int> kAtomsWithAttributionChain;\n"); - fprintf(out, - " const static std::map<int, StateAtomFieldOptions> " - "kStateAtomsFieldOptions;\n"); - fprintf(out, - " const static std::map<int, std::vector<int>> " - "kBytesFieldAtoms;"); - fprintf(out, - " const static std::set<int> kWhitelistedAtoms;\n"); - fprintf(out, "};\n"); - - fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", - maxPushedAtomId); - } - - // Print write methods - fprintf(out, "//\n"); - fprintf(out, "// Write methods\n"); - fprintf(out, "//\n"); - write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl, - moduleName); - - fprintf(out, "//\n"); - fprintf(out, "// Write flattened methods\n"); - fprintf(out, "//\n"); - write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules, - attributionDecl, moduleName); - - fprintf(out, "\n"); - write_closing_namespace(out, cppNamespace); - - return 0; -} - -static void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, - const AtomDecl& atom) { - fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", - method_name.c_str(), atom_code_name.c_str()); - for (vector<AtomField>::const_iterator field = atom.fields.begin(); - field != atom.fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - fprintf(out, ", android.os.WorkSource workSource"); - } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", SparseArray<Object> value_map"); - } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, ", byte[] %s", field->name.c_str()); - } else { - fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str()); - } - } - fprintf(out, ");<br>\n"); -} - -static void write_java_method( - FILE* out, - const string& method_name, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const AtomDecl &attributionDecl) { - - for (auto signature_to_modules_it = signatures_to_modules.begin(); - signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { - vector<java_type_t> signature = signature_to_modules_it->first; - fprintf(out, " /** @hide */\n"); - fprintf(out, " public static native int %s(int code", method_name.c_str()); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", - java_type_name(chainField.javaType), chainField.name.c_str()); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", SparseArray<Object> value_map"); - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - } -} - -static void write_java_helpers_for_module( - FILE * out, - const AtomDecl &attributionDecl, - const int requiredHelpers) { - fprintf(out, " private static void copyInt(byte[] buff, int pos, int val) {\n"); - fprintf(out, " buff[pos] = (byte) (val);\n"); - fprintf(out, " buff[pos + 1] = (byte) (val >> 8);\n"); - fprintf(out, " buff[pos + 2] = (byte) (val >> 16);\n"); - fprintf(out, " buff[pos + 3] = (byte) (val >> 24);\n"); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - - fprintf(out, " private static void copyLong(byte[] buff, int pos, long val) {\n"); - fprintf(out, " buff[pos] = (byte) (val);\n"); - fprintf(out, " buff[pos + 1] = (byte) (val >> 8);\n"); - fprintf(out, " buff[pos + 2] = (byte) (val >> 16);\n"); - fprintf(out, " buff[pos + 3] = (byte) (val >> 24);\n"); - fprintf(out, " buff[pos + 4] = (byte) (val >> 32);\n"); - fprintf(out, " buff[pos + 5] = (byte) (val >> 40);\n"); - fprintf(out, " buff[pos + 6] = (byte) (val >> 48);\n"); - fprintf(out, " buff[pos + 7] = (byte) (val >> 56);\n"); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - - if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) { - fprintf(out, " private static void copyFloat(byte[] buff, int pos, float val) {\n"); - fprintf(out, " copyInt(buff, pos, Float.floatToIntBits(val));\n"); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } - - if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) { - fprintf(out, " private static void writeAttributionChain(byte[] buff, int pos"); - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", - java_type_name(chainField.javaType), chainField.name.c_str()); - } - fprintf(out, ") {\n"); - - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - - // Write the first list begin. - fprintf(out, " buff[pos] = LIST_TYPE;\n"); - fprintf(out, " buff[pos + 1] = (byte) (%s.length);\n", tagName); - fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n"); - - // Iterate through the attribution chain and write the nodes. - fprintf(out, " for (int i = 0; i < %s.length; i++) {\n", tagName); - // Write the list begin. - fprintf(out, " buff[pos] = LIST_TYPE;\n"); - fprintf(out, " buff[pos + 1] = %lu;\n", attributionDecl.fields.size()); - fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n"); - - // Write the uid. - fprintf(out, " buff[pos] = INT_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, %s[i]);\n", uidName); - fprintf(out, " pos += INT_TYPE_SIZE;\n"); - - // Write the tag. - fprintf(out, " String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", - tagName, tagName, tagName); - fprintf(out, " byte[] %sByte = %sStr.getBytes(UTF_8);\n", tagName, tagName); - fprintf(out, " buff[pos] = STRING_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, %sByte.length);\n", tagName); - fprintf(out, " System.arraycopy(" - "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n", - tagName, tagName); - fprintf(out, " pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", tagName); - fprintf(out, " }\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } -} - - -static int write_java_non_chained_method_for_module( - FILE* out, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const string& moduleName - ) { - for (auto signature_to_modules_it = signatures_to_modules.begin(); - signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { - // Skip if this signature is not needed for the module. - if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { - continue; - } - - // Print method signature. - vector<java_type_t> signature = signature_to_modules_it->first; - fprintf(out, " public static void write_non_chained(int code"); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - // Non chained signatures should not have attribution chains. - return 1; - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - // Module logging does not yet support key value pair. - return 1; - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - fprintf(out, " write(code"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - // First two args are uid and tag of attribution chain. - if (argIndex == 1) { - fprintf(out, ", new int[] {arg%d}", argIndex); - } else if (argIndex == 2) { - fprintf(out, ", new java.lang.String[] {arg%d}", argIndex); - } else { - fprintf(out, ", arg%d", argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } - return 0; -} - -static int write_java_method_for_module( - FILE* out, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const AtomDecl &attributionDecl, - const string& moduleName, - int* requiredHelpers - ) { - - for (auto signature_to_modules_it = signatures_to_modules.begin(); - signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { - // Skip if this signature is not needed for the module. - if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { - continue; - } - - // Print method signature. - vector<java_type_t> signature = signature_to_modules_it->first; - fprintf(out, " public static void write(int code"); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", - java_type_name(chainField.javaType), chainField.name.c_str()); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - // Module logging does not yet support key value pair. - return 1; - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - // Calculate the size of the buffer. - fprintf(out, " // Initial overhead of the list, timestamp, and atom tag.\n"); - fprintf(out, " int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - switch (*arg) { - case JAVA_TYPE_BOOLEAN: - case JAVA_TYPE_INT: - case JAVA_TYPE_FLOAT: - case JAVA_TYPE_ENUM: - fprintf(out, " needed += INT_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_LONG: - // Longs take 9 bytes, 1 for the type and 8 for the value. - fprintf(out, " needed += LONG_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_STRING: - // Strings take 5 metadata bytes + length of byte encoded string. - fprintf(out, " if (arg%d == null) {\n", argIndex); - fprintf(out, " arg%d = \"\";\n", argIndex); - fprintf(out, " }\n"); - fprintf(out, " byte[] arg%dBytes= arg%d.getBytes(UTF_8);\n", - argIndex, argIndex); - fprintf(out, " needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", - argIndex); - break; - case JAVA_TYPE_BYTE_ARRAY: - // Byte arrays take 5 metadata bytes + length of byte array. - fprintf(out, " if (arg%d == null) {\n", argIndex); - fprintf(out, " arg%d = new byte[0];\n", argIndex); - fprintf(out, " }\n"); - fprintf(out, " needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex); - break; - case JAVA_TYPE_ATTRIBUTION_CHAIN: - { - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - // Null checks on the params. - fprintf(out, " if (%s == null) {\n", uidName); - fprintf(out, " %s = new %s[0];\n", uidName, - java_type_name(attributionDecl.fields.front().javaType)); - fprintf(out, " }\n"); - fprintf(out, " if (%s == null) {\n", tagName); - fprintf(out, " %s = new %s[0];\n", tagName, - java_type_name(attributionDecl.fields.back().javaType)); - fprintf(out, " }\n"); - - // First check that the lengths of the uid and tag arrays are the same. - fprintf(out, " if (%s.length != %s.length) {\n", uidName, tagName); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - fprintf(out, " int attrSize = LIST_TYPE_OVERHEAD;\n"); - fprintf(out, " for (int i = 0; i < %s.length; i++) {\n", tagName); - fprintf(out, " String str%d = (%s[i] == null) ? \"\" : %s[i];\n", - argIndex, tagName, tagName); - fprintf(out, " int str%dlen = str%d.getBytes(UTF_8).length;\n", - argIndex, argIndex); - fprintf(out, - " attrSize += " - "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n", - argIndex); - fprintf(out, " }\n"); - fprintf(out, " needed += attrSize;\n"); - break; - } - default: - // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR. - return 1; - } - argIndex++; - } - - // Now we have the size that is needed. Check for overflow and return if needed. - fprintf(out, " if (needed > MAX_EVENT_PAYLOAD) {\n"); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - - // Create new buffer, and associated data types. - fprintf(out, " byte[] buff = new byte[needed];\n"); - fprintf(out, " int pos = 0;\n"); - - // Initialize the buffer with list data type. - fprintf(out, " buff[pos] = LIST_TYPE;\n"); - fprintf(out, " buff[pos + 1] = %zu;\n", signature.size() + 2); - fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n"); - - // Write timestamp. - fprintf(out, " long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n"); - fprintf(out, " buff[pos] = LONG_TYPE;\n"); - fprintf(out, " copyLong(buff, pos + 1, elapsedRealtime);\n"); - fprintf(out, " pos += LONG_TYPE_SIZE;\n"); - - // Write atom code. - fprintf(out, " buff[pos] = INT_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, code);\n"); - fprintf(out, " pos += INT_TYPE_SIZE;\n"); - - // Write the args. - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - switch (*arg) { - case JAVA_TYPE_BOOLEAN: - fprintf(out, " buff[pos] = INT_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, arg%d? 1 : 0);\n", argIndex); - fprintf(out, " pos += INT_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - fprintf(out, " buff[pos] = INT_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, arg%d);\n", argIndex); - fprintf(out, " pos += INT_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_FLOAT: - *requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT; - fprintf(out, " buff[pos] = FLOAT_TYPE;\n"); - fprintf(out, " copyFloat(buff, pos + 1, arg%d);\n", argIndex); - fprintf(out, " pos += FLOAT_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_LONG: - fprintf(out, " buff[pos] = LONG_TYPE;\n"); - fprintf(out, " copyLong(buff, pos + 1, arg%d);\n", argIndex); - fprintf(out, " pos += LONG_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_STRING: - fprintf(out, " buff[pos] = STRING_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, arg%dBytes.length);\n", argIndex); - fprintf(out, " System.arraycopy(" - "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n", - argIndex, argIndex); - fprintf(out, " pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", - argIndex); - break; - case JAVA_TYPE_BYTE_ARRAY: - fprintf(out, " buff[pos] = STRING_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, arg%d.length);\n", argIndex); - fprintf(out, " System.arraycopy(" - "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n", - argIndex, argIndex); - fprintf(out, " pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex); - break; - case JAVA_TYPE_ATTRIBUTION_CHAIN: - { - *requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION; - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - - fprintf(out, " writeAttributionChain(buff, pos, %s, %s);\n", - uidName, tagName); - fprintf(out, " pos += attrSize;\n"); - break; - } - default: - // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR. - return 1; - } - argIndex++; - } - - fprintf(out, " StatsLog.writeRaw(buff, pos);\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } - return 0; -} - -static void write_java_work_source_method(FILE* out, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const string& moduleName) { - fprintf(out, "\n // WorkSource methods.\n"); - for (auto signature_to_modules_it = signatures_to_modules.begin(); - signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { - // Skip if this signature is not needed for the module. - if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_to_modules_it->first; - // Determine if there is Attribution in this signature. - int attributionArg = -1; - int argIndexMax = 0; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - argIndexMax++; - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - if (attributionArg > -1) { - fprintf(stderr, "An atom contains multiple AttributionNode fields.\n"); - fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n"); - fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n"); - return; - } - attributionArg = argIndexMax; - } - } - if (attributionArg < 0) { - continue; - } - - // Method header (signature) - if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, " /** @hide */\n"); - } - fprintf(out, " public static void write(int code"); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - fprintf(out, ", WorkSource ws"); - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - // write_non_chained() component. TODO: Remove when flat uids are no longer needed. - fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n"); - fprintf(out, " write_non_chained(code"); - for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { - if (argIndex == attributionArg) { - fprintf(out, ", ws.get(i), ws.getName(i)"); - } else { - fprintf(out, ", arg%d", argIndex); - } - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); // close for-loop - - // write() component. - fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n"); - fprintf(out, " if (workChains != null) {\n"); - fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n"); - fprintf(out, " write(code"); - for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { - if (argIndex == attributionArg) { - fprintf(out, ", wc.getUids(), wc.getTags()"); - } else { - fprintf(out, ", arg%d", argIndex); - } - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); // close for-loop - fprintf(out, " }\n"); // close if - fprintf(out, " }\n"); // close method - } -} - -static void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) { - fprintf(out, " // Constants for atom codes.\n"); - - std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map; - build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); - - // Print constants for the atom codes. - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - // Skip if the atom is not needed for the module. - if (!atom_needed_for_module(*atom, moduleName)) { - continue; - } - string constant = make_constant_name(atom->name); - fprintf(out, "\n"); - fprintf(out, " /**\n"); - fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str()); - write_java_usage(out, "write", constant, *atom); - auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); - if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { - write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second); - } - if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, " * @hide\n"); - } - fprintf(out, " */\n"); - fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code); - } - fprintf(out, "\n"); -} - -static void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName) { - fprintf(out, " // Constants for enum values.\n\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - // Skip if the atom is not needed for the module. - if (!atom_needed_for_module(*atom, moduleName)) { - continue; - } - for (vector<AtomField>::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ENUM) { - fprintf(out, " // Values for %s.%s\n", atom->message.c_str(), - field->name.c_str()); - for (map<int, string>::const_iterator value = field->enumValues.begin(); - value != field->enumValues.end(); value++) { - if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, " /** @hide */\n"); - } - fprintf(out, " public static final int %s__%s__%s = %d;\n", - make_constant_name(atom->message).c_str(), - make_constant_name(field->name).c_str(), - make_constant_name(value->second).c_str(), - value->first); - } - fprintf(out, "\n"); - } - } - } -} - -static int -write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) -{ - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "package android.util;\n"); - fprintf(out, "\n"); - fprintf(out, "import android.os.WorkSource;\n"); - fprintf(out, "import android.util.SparseArray;\n"); - fprintf(out, "import java.util.ArrayList;\n"); - fprintf(out, "\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * API For logging statistics events.\n"); - fprintf(out, " * @hide\n"); - fprintf(out, " */\n"); - fprintf(out, "public class StatsLogInternal {\n"); - write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME); - - write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME); - - // Print write methods - fprintf(out, " // Write methods\n"); - write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl); - write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules, - attributionDecl); - write_java_work_source_method(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME); - - fprintf(out, "}\n"); - - return 0; -} - -// TODO: Merge this with write_stats_log_java so that we can get rid of StatsLogInternal JNI. -static int -write_stats_log_java_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, - const string& moduleName, const string& javaClass, const string& javaPackage) -{ - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "package %s;\n", javaPackage.c_str()); - fprintf(out, "\n"); - fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n"); - fprintf(out, "\n"); - fprintf(out, "import android.util.StatsLog;\n"); - fprintf(out, "import android.os.SystemClock;\n"); - fprintf(out, "\n"); - fprintf(out, "import java.util.ArrayList;\n"); - fprintf(out, "\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * Utility class for logging statistics events.\n"); - fprintf(out, " */\n"); - fprintf(out, "public class %s {\n", javaClass.c_str()); - - // TODO: ideally these match with the native values (and automatically change if they change). - fprintf(out, " private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n"); - fprintf(out, - " private static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n"); - // Value types. Must match with EventLog.java and log.h. - fprintf(out, " private static final byte INT_TYPE = 0;\n"); - fprintf(out, " private static final byte LONG_TYPE = 1;\n"); - fprintf(out, " private static final byte STRING_TYPE = 2;\n"); - fprintf(out, " private static final byte LIST_TYPE = 3;\n"); - fprintf(out, " private static final byte FLOAT_TYPE = 4;\n"); - - // Size of each value type. - // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value. - fprintf(out, " private static final int INT_TYPE_SIZE = 5;\n"); - fprintf(out, " private static final int FLOAT_TYPE_SIZE = 5;\n"); - // Longs take 9 bytes, 1 for the type and 8 for the value. - fprintf(out, " private static final int LONG_TYPE_SIZE = 9;\n"); - // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length. - fprintf(out, " private static final int STRING_TYPE_OVERHEAD = 5;\n"); - fprintf(out, " private static final int LIST_TYPE_OVERHEAD = 2;\n"); - - write_java_atom_codes(out, atoms, moduleName); - - write_java_enum_values(out, atoms, moduleName); - - int errors = 0; - int requiredHelpers = 0; - // Print write methods - fprintf(out, " // Write methods\n"); - errors += write_java_method_for_module(out, atoms.signatures_to_modules, attributionDecl, - moduleName, &requiredHelpers); - errors += write_java_non_chained_method_for_module(out, atoms.non_chained_signatures_to_modules, - moduleName); - - fprintf(out, " // Helper methods for copying primitives\n"); - write_java_helpers_for_module(out, attributionDecl, requiredHelpers); - - fprintf(out, "}\n"); - - return errors; -} - +// Hide the JNI write helpers that are not used in the new schema. +// TODO(b/145100015): Remove this and other JNI related functionality once StatsEvent migration is +// complete. +#if defined(STATS_SCHEMA_LEGACY) +// JNI helpers. static const char* jni_type_name(java_type_t type) { @@ -1666,7 +203,7 @@ static void write_key_value_map_jni(FILE* out) { } static int -write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name, +write_stats_log_jni_method(FILE* out, const string& java_method_name, const string& cpp_method_name, const map<vector<java_type_t>, set<string>>& signatures_to_modules, const AtomDecl &attributionDecl) { // Print write methods @@ -1882,40 +419,56 @@ void write_jni_registration(FILE* out, const string& java_method_name, jni_function_name(java_method_name, signature).c_str()); } } +#endif // JNI helpers. static int +#if defined(STATS_SCHEMA_LEGACY) write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) +#else +// Write empty JNI file that doesn't contain any JNI methods. +// TODO(b/145100015): remove this function and all JNI autogen code once StatsEvent migration is +// complete. +write_stats_log_jni(FILE* out) +#endif { // Print prelude fprintf(out, "// This file is autogenerated\n"); fprintf(out, "\n"); +#if defined(STATS_SCHEMA_LEGACY) fprintf(out, "#include <statslog.h>\n"); fprintf(out, "\n"); fprintf(out, "#include <nativehelper/JNIHelp.h>\n"); fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n"); fprintf(out, "#include <utils/Vector.h>\n"); +#endif fprintf(out, "#include \"core_jni_helpers.h\"\n"); fprintf(out, "#include \"jni.h\"\n"); fprintf(out, "\n"); +#if defined(STATS_SCHEMA_LEGACY) fprintf(out, "#define UNUSED __attribute__((__unused__))\n"); fprintf(out, "\n"); +#endif fprintf(out, "namespace android {\n"); fprintf(out, "\n"); - write_stats_log_jni(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl); - write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained", +#if defined(STATS_SCHEMA_LEGACY) + write_stats_log_jni_method(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl); + write_stats_log_jni_method(out, "write_non_chained", "stats_write_non_chained", atoms.non_chained_signatures_to_modules, attributionDecl); +#endif // Print registration function table fprintf(out, "/*\n"); fprintf(out, " * JNI registration.\n"); fprintf(out, " */\n"); fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n"); +#if defined(STATS_SCHEMA_LEGACY) write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl); write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules, attributionDecl); +#endif fprintf(out, "};\n"); fprintf(out, "\n"); @@ -1938,20 +491,28 @@ print_usage() fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n"); fprintf(stderr, "\n"); fprintf(stderr, "OPTIONS\n"); - fprintf(stderr, " --cpp FILENAME the header file to output\n"); - fprintf(stderr, " --header FILENAME the cpp file to output\n"); + fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n"); + fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n"); + fprintf(stderr, + " --atomsInfoCpp FILENAME the header file to output for statsd metadata\n"); + fprintf(stderr, " --atomsInfoHeader FILENAME the cpp file to output for statsd metadata\n"); fprintf(stderr, " --help this message\n"); fprintf(stderr, " --java FILENAME the java file to output\n"); fprintf(stderr, " --jni FILENAME the jni file to output\n"); fprintf(stderr, " --module NAME optional, module name to generate outputs for\n"); fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n"); fprintf(stderr, " comma separated namespace of the files\n"); - fprintf(stderr, " --importHeader NAME required for cpp/jni to say which header to import\n"); + fprintf(stderr," --importHeader NAME required for cpp/jni to say which header to import " + "for write helpers\n"); + fprintf(stderr," --atomsInfoImportHeader NAME required for cpp to say which header to import " + "for statsd metadata\n"); fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n"); fprintf(stderr, " required for java with module\n"); fprintf(stderr, " --javaClass CLASS the class name of the java class.\n"); fprintf(stderr, " Optional for Java with module.\n"); - fprintf(stderr, " Default is \"StatsLogInternal\"\n");} + fprintf(stderr, " Default is \"StatsLogInternal\"\n"); + fprintf(stderr, " --supportQ Include support for Android Q.\n"); +} /** * Do the argument parsing and execute the tasks. @@ -1963,12 +524,16 @@ run(int argc, char const*const* argv) string headerFilename; string javaFilename; string jniFilename; + string atomsInfoCppFilename; + string atomsInfoHeaderFilename; string moduleName = DEFAULT_MODULE_NAME; string cppNamespace = DEFAULT_CPP_NAMESPACE; string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT; + string atomsInfoCppHeaderImport = DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT; string javaPackage = DEFAULT_JAVA_PACKAGE; string javaClass = DEFAULT_JAVA_CLASS; + bool supportQ = false; int index = 1; while (index < argc) { @@ -2038,18 +603,50 @@ run(int argc, char const*const* argv) return 1; } javaClass = argv[index]; + } else if (0 == strcmp("--atomsInfoHeader", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + atomsInfoHeaderFilename = argv[index]; + } else if (0 == strcmp("--atomsInfoCpp", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + atomsInfoCppFilename = argv[index]; + } else if (0 == strcmp("--atomsInfoImportHeader", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + atomsInfoCppHeaderImport = argv[index]; + } else if (0 == strcmp("--supportQ", argv[index])) { + supportQ = true; } + index++; } if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0 - && jniFilename.size() == 0) { + && jniFilename.size() == 0 + && atomsInfoHeaderFilename.size() == 0 + && atomsInfoCppFilename.size() == 0) { print_usage(); return 1; } + if (DEFAULT_MODULE_NAME == moduleName && supportQ) { + // Support for Q schema is not needed for default module. + fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str()); + return 1; + } + // Collate the parameters Atoms atoms; int errorCount = collate_atoms(Atom::descriptor(), &atoms); @@ -2062,6 +659,30 @@ run(int argc, char const*const* argv) collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl, &attributionSignature); + // Write the atoms info .cpp file + if (atomsInfoCppFilename.size() != 0) { + FILE* out = fopen(atomsInfoCppFilename.c_str(), "w"); + if (out == NULL) { + fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoCppFilename.c_str()); + return 1; + } + errorCount = android::stats_log_api_gen::write_atoms_info_cpp( + out, atoms, cppNamespace, atomsInfoCppHeaderImport, cppHeaderImport); + fclose(out); + } + + // Write the atoms info .h file + if (atomsInfoHeaderFilename.size() != 0) { + FILE* out = fopen(atomsInfoHeaderFilename.c_str(), "w"); + if (out == NULL) { + fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoHeaderFilename.c_str()); + return 1; + } + errorCount = android::stats_log_api_gen::write_atoms_info_header(out, atoms, cppNamespace); + fclose(out); + } + + // Write the .cpp file if (cppFilename.size() != 0) { FILE* out = fopen(cppFilename.c_str(), "w"); @@ -2080,7 +701,7 @@ run(int argc, char const*const* argv) return 1; } errorCount = android::stats_log_api_gen::write_stats_log_cpp( - out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport); + out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport, supportQ); fclose(out); } @@ -2112,13 +733,25 @@ run(int argc, char const*const* argv) fprintf(stderr, "Must supply --javaPackage if supplying a specific module\n"); return 1; } + +#if defined(STATS_SCHEMA_LEGACY) if (moduleName == DEFAULT_MODULE_NAME) { - errorCount = android::stats_log_api_gen::write_stats_log_java( + errorCount = android::stats_log_api_gen::write_stats_log_java_q( out, atoms, attributionDecl); } else { - errorCount = android::stats_log_api_gen::write_stats_log_java_for_module( + errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module( out, atoms, attributionDecl, moduleName, javaClass, javaPackage); + + } +#else + if (moduleName == DEFAULT_MODULE_NAME) { + javaClass = "StatsLogInternal"; + javaPackage = "android.util"; } + errorCount = android::stats_log_api_gen::write_stats_log_java( + out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ); +#endif + fclose(out); } @@ -2129,16 +762,22 @@ run(int argc, char const*const* argv) fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str()); return 1; } + +#if defined(STATS_SCHEMA_LEGACY) errorCount = android::stats_log_api_gen::write_stats_log_jni( out, atoms, attributionDecl); +#else + errorCount = android::stats_log_api_gen::write_stats_log_jni(out); +#endif + fclose(out); } return errorCount; } -} -} +} // namespace stats_log_api_gen +} // namespace android /** * Main. diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp new file mode 100644 index 000000000000..c7a34feff94b --- /dev/null +++ b/tools/stats_log_api_gen/native_writer.cpp @@ -0,0 +1,342 @@ +/* + * 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 "native_writer.h" +#include "native_writer_q.h" +#include "utils.h" + +namespace android { +namespace stats_log_api_gen { + +#if !defined(STATS_SCHEMA_LEGACY) +static void write_native_key_value_pairs_for_type(FILE* out, const int argIndex, + const int typeIndex, const string& type, const string& valueFieldName) { + fprintf(out, " for (const auto& it : arg%d_%d) {\n", argIndex, typeIndex); + fprintf(out, " pairs.push_back(" + "{ .key = it.first, .valueType = %s, .%s = it.second });\n", + type.c_str(), valueFieldName.c_str()); + fprintf(out, " }\n"); + +} + +static int write_native_stats_write_methods(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName, const bool supportQ) { + fprintf(out, "\n"); + for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); + signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_to_modules_it->first; + + write_native_method_signature(out, "int stats_write", signature, + attributionDecl, " {"); + + int argIndex = 1; + if (supportQ) { + fprintf(out, " StatsEventCompat event;\n"); + fprintf(out, " event.setAtomId(code);\n"); + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_ATTRIBUTION_CHAIN: { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + fprintf(out, " event.writeAttributionChain(%s, %s_length, %s);\n", + uidName, uidName, tagName); + break; + } + case JAVA_TYPE_KEY_VALUE_PAIR: + fprintf(out, " event.writeKeyValuePairs(" + "arg%d_1, arg%d_2, arg%d_3, arg%d_4);\n", + argIndex, argIndex, argIndex, argIndex); + break; + case JAVA_TYPE_BYTE_ARRAY: + fprintf(out, " event.writeByteArray(arg%d.arg, arg%d.arg_length);\n", + argIndex, argIndex); + break; + case JAVA_TYPE_BOOLEAN: + fprintf(out, " event.writeBool(arg%d);\n", argIndex); + break; + case JAVA_TYPE_INT: // Fall through. + case JAVA_TYPE_ENUM: + fprintf(out, " event.writeInt32(arg%d);\n", argIndex); + break; + case JAVA_TYPE_FLOAT: + fprintf(out, " event.writeFloat(arg%d);\n", argIndex); + break; + case JAVA_TYPE_LONG: + fprintf(out, " event.writeInt64(arg%d);\n", argIndex); + break; + case JAVA_TYPE_STRING: + fprintf(out, " event.writeString(arg%d);\n", argIndex); + break; + default: + // Unsupported types: OBJECT, DOUBLE. + fprintf(stderr, "Encountered unsupported type."); + return 1; + } + argIndex++; + } + fprintf(out, " return event.writeToSocket();\n"); + } else { + fprintf(out, " struct stats_event* event = stats_event_obtain();\n"); + fprintf(out, " stats_event_set_atom_id(event, code);\n"); + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_ATTRIBUTION_CHAIN: { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + fprintf(out, + " stats_event_write_attribution_chain(event, " + "reinterpret_cast<const uint32_t*>(%s), %s.data(), " + "static_cast<uint8_t>(%s_length));\n", + uidName, tagName, uidName); + break; + } + case JAVA_TYPE_KEY_VALUE_PAIR: + fprintf(out, " std::vector<key_value_pair> pairs;\n"); + write_native_key_value_pairs_for_type( + out, argIndex, 1, "INT32_TYPE", "int32Value"); + write_native_key_value_pairs_for_type( + out, argIndex, 2, "INT64_TYPE", "int64Value"); + write_native_key_value_pairs_for_type( + out, argIndex, 3, "STRING_TYPE", "stringValue"); + write_native_key_value_pairs_for_type( + out, argIndex, 4, "FLOAT_TYPE", "floatValue"); + fprintf(out, + " stats_event_write_key_value_pairs(event, pairs.data(), " + "static_cast<uint8_t>(pairs.size()));\n"); + break; + case JAVA_TYPE_BYTE_ARRAY: + fprintf(out, + " stats_event_write_byte_array(event, " + "reinterpret_cast<const uint8_t*>(arg%d.arg), arg%d.arg_length);\n", + argIndex, argIndex); + break; + case JAVA_TYPE_BOOLEAN: + fprintf(out, " stats_event_write_bool(event, arg%d);\n", argIndex); + break; + case JAVA_TYPE_INT: // Fall through. + case JAVA_TYPE_ENUM: + fprintf(out, " stats_event_write_int32(event, arg%d);\n", argIndex); + break; + case JAVA_TYPE_FLOAT: + fprintf(out, " stats_event_write_float(event, arg%d);\n", argIndex); + break; + case JAVA_TYPE_LONG: + fprintf(out, " stats_event_write_int64(event, arg%d);\n", argIndex); + break; + case JAVA_TYPE_STRING: + fprintf(out, " stats_event_write_string8(event, arg%d);\n", argIndex); + break; + default: + // Unsupported types: OBJECT, DOUBLE. + fprintf(stderr, "Encountered unsupported type."); + return 1; + } + argIndex++; + } + fprintf(out, " const int ret = stats_event_write(event);\n"); + fprintf(out, " stats_event_release(event);\n"); + fprintf(out, " return ret;\n"); + } + fprintf(out, "}\n\n"); + } + return 0; +} + +static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName) { + fprintf(out, "\n"); + for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); + signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { + if (!signature_needed_for_module(signature_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_it->first; + + write_native_method_signature(out, "int stats_write_non_chained", signature, + attributionDecl, " {"); + + vector<java_type_t> newSignature; + + // First two args form the attribution node so size goes down by 1. + newSignature.reserve(signature.size() - 1); + + // First arg is Attribution Chain. + newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN); + + // Followed by the originial signature except the first 2 args. + newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end()); + + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + fprintf(out, " const int32_t* %s = &arg1;\n", uidName); + fprintf(out, " const size_t %s_length = 1;\n", uidName); + fprintf(out, " const std::vector<char const*> %s(1, arg2);\n", tagName); + fprintf(out, " return "); + write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2); + + fprintf(out, "}\n\n"); + } + +} +#endif + +static void write_native_method_header( + FILE* out, + const string& methodName, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, const string& moduleName) { + + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + // Skip if this signature is not needed for the module. + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + + vector<java_type_t> signature = signature_to_modules_it->first; + write_native_method_signature(out, methodName, signature, attributionDecl, ";"); + } +} + +int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace, + const string& importHeader, const bool supportQ) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + + fprintf(out, "#include <%s>\n", importHeader.c_str()); +#if defined(STATS_SCHEMA_LEGACY) + (void)supportQ; // Workaround for unused parameter error. + write_native_cpp_includes_q(out); +#else + if (supportQ) { + fprintf(out, "#include <StatsEventCompat.h>\n"); + } else { + fprintf(out, "#include <stats_event.h>\n"); + } +#endif + + fprintf(out, "\n"); + write_namespace(out, cppNamespace); + +#if defined(STATS_SCHEMA_LEGACY) + write_native_stats_log_cpp_globals_q(out); + write_native_get_timestamp_ns_q(out); + write_native_try_stats_write_methods_q(out, atoms, attributionDecl, moduleName); + write_native_stats_write_methods_q(out, "int stats_write", atoms, attributionDecl, moduleName, + "try_stats_write"); + write_native_try_stats_write_non_chained_methods_q(out, atoms, attributionDecl, moduleName); + write_native_stats_write_non_chained_methods_q(out, "int stats_write_non_chained", atoms, + attributionDecl, moduleName, "try_stats_write_non_chained"); +#else + write_native_stats_write_methods(out, atoms, attributionDecl, moduleName, supportQ); + write_native_stats_write_non_chained_methods(out, atoms, attributionDecl, moduleName); +#endif + + // Print footer + fprintf(out, "\n"); + write_closing_namespace(out, cppNamespace); + + return 0; +} + +int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "#pragma once\n"); + fprintf(out, "\n"); + fprintf(out, "#include <stdint.h>\n"); + fprintf(out, "#include <vector>\n"); + fprintf(out, "#include <map>\n"); + fprintf(out, "#include <set>\n"); + fprintf(out, "\n"); + + write_namespace(out, cppNamespace); + fprintf(out, "\n"); + fprintf(out, "/*\n"); + fprintf(out, " * API For logging statistics events.\n"); + fprintf(out, " */\n"); + fprintf(out, "\n"); + + write_native_atom_constants(out, atoms, attributionDecl, moduleName); + + // Print constants for the enum values. + fprintf(out, "//\n"); + fprintf(out, "// Constants for enum values\n"); + fprintf(out, "//\n\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + // Skip if the atom is not needed for the module. + if (!atom_needed_for_module(*atom, moduleName)) { + continue; + } + + for (vector<AtomField>::const_iterator field = atom->fields.begin(); + field != atom->fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ENUM) { + fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), + field->name.c_str()); + for (map<int, string>::const_iterator value = field->enumValues.begin(); + value != field->enumValues.end(); value++) { + fprintf(out, "const int32_t %s__%s__%s = %d;\n", + make_constant_name(atom->message).c_str(), + make_constant_name(field->name).c_str(), + make_constant_name(value->second).c_str(), + value->first); + } + fprintf(out, "\n"); + } + } + } + + fprintf(out, "struct BytesField {\n"); + fprintf(out, + " BytesField(char const* array, size_t len) : arg(array), " + "arg_length(len) {}\n"); + fprintf(out, " char const* arg;\n"); + fprintf(out, " size_t arg_length;\n"); + fprintf(out, "};\n"); + fprintf(out, "\n"); + + // Print write methods + fprintf(out, "//\n"); + fprintf(out, "// Write methods\n"); + fprintf(out, "//\n"); + write_native_method_header(out, "int stats_write", atoms.signatures_to_modules, attributionDecl, + moduleName); + + fprintf(out, "//\n"); + fprintf(out, "// Write flattened methods\n"); + fprintf(out, "//\n"); + write_native_method_header(out, "int stats_write_non_chained", + atoms.non_chained_signatures_to_modules, attributionDecl, moduleName); + + fprintf(out, "\n"); + write_closing_namespace(out, cppNamespace); + + return 0; +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h new file mode 100644 index 000000000000..aafa96ece2d0 --- /dev/null +++ b/tools/stats_log_api_gen/native_writer.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace, const string& importHeader, + const bool supportQ); + +int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace); + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/native_writer_q.cpp b/tools/stats_log_api_gen/native_writer_q.cpp new file mode 100644 index 000000000000..299873dad975 --- /dev/null +++ b/tools/stats_log_api_gen/native_writer_q.cpp @@ -0,0 +1,276 @@ +/* + * 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 "native_writer_q.h" +#include "utils.h" + +namespace android { +namespace stats_log_api_gen { + +static void write_native_stats_write_body_q(FILE* out, const vector<java_type_t>& signature, + const AtomDecl& attributionDecl, const string& indent, const string& tryMethodName) { + fprintf(out, "%sint ret = 0;\n", indent.c_str()); + + fprintf(out, "%sfor(int retry = 0; retry < 2; ++retry) {\n", indent.c_str()); + fprintf(out, "%s ret = ", indent.c_str()); + write_native_method_call(out, tryMethodName, signature, attributionDecl); + fprintf(out, "%s if (ret >= 0) { break; }\n", indent.c_str()); + + fprintf(out, "%s {\n", indent.c_str()); + fprintf(out, "%s std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n", indent.c_str()); + fprintf(out, "%s if ((get_elapsed_realtime_ns() - lastRetryTimestampNs) <= " + "kMinRetryIntervalNs) break;\n", indent.c_str()); + fprintf(out, "%s lastRetryTimestampNs = get_elapsed_realtime_ns();\n", + indent.c_str()); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s std::this_thread::sleep_for(std::chrono::milliseconds(10));\n", + indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "%sif (ret < 0) {\n", indent.c_str()); + fprintf(out, "%s note_log_drop(ret, code);\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "%sreturn ret;\n", indent.c_str()); +} + +void write_native_cpp_includes_q(FILE* out) { + fprintf(out, "#include <mutex>\n"); + fprintf(out, "#include <chrono>\n"); + fprintf(out, "#include <thread>\n"); + fprintf(out, "#ifdef __ANDROID__\n"); + fprintf(out, "#include <cutils/properties.h>\n"); + fprintf(out, "#endif\n"); + fprintf(out, "#include <stats_event_list.h>\n"); + fprintf(out, "#include <log/log.h>\n"); + fprintf(out, "#include <time.h>\n"); +} + +void write_native_get_timestamp_ns_q(FILE* out) { + fprintf(out, "\n"); + fprintf(out, "static int64_t get_elapsed_realtime_ns() {\n"); + fprintf(out, " struct timespec t;\n"); + fprintf(out, " t.tv_sec = t.tv_nsec = 0;\n"); + fprintf(out, " clock_gettime(CLOCK_BOOTTIME, &t);\n"); + fprintf(out, " return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;\n"); + fprintf(out, "}\n"); +} + +void write_native_stats_log_cpp_globals_q(FILE* out) { + fprintf(out, "// the single event tag id for all stats logs\n"); + fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); + fprintf(out, "#ifdef __ANDROID__\n"); + fprintf(out, + "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n"); + fprintf(out, "#else\n"); + fprintf(out, "const static bool kStatsdEnabled = false;\n"); + fprintf(out, "#endif\n"); + + fprintf(out, "int64_t lastRetryTimestampNs = -1;\n"); + fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n"); + fprintf(out, "static std::mutex mLogdRetryMutex;\n"); +} + +void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName) { + fprintf(out, "\n"); + for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); + signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_to_modules_it->first; + + write_native_method_signature(out, "static int try_stats_write", signature, + attributionDecl, " {"); + + int argIndex = 1; + fprintf(out, " if (kStatsdEnabled) {\n"); + fprintf(out, " stats_event_list event(kStatsEventTag);\n"); + fprintf(out, " event << get_elapsed_realtime_ns();\n\n"); + fprintf(out, " event << code;\n\n"); + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (const auto &chainField : attributionDecl.fields) { + if (chainField.javaType == JAVA_TYPE_STRING) { + fprintf(out, " if (%s_length != %s.size()) {\n", + attributionDecl.fields.front().name.c_str(), chainField.name.c_str()); + fprintf(out, " return -EINVAL;\n"); + fprintf(out, " }\n"); + } + } + fprintf(out, "\n event.begin();\n"); + fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n", + attributionDecl.fields.front().name.c_str()); + fprintf(out, " event.begin();\n"); + for (const auto &chainField : attributionDecl.fields) { + if (chainField.javaType == JAVA_TYPE_STRING) { + fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str()); + fprintf(out, " event << %s[i];\n", chainField.name.c_str()); + fprintf(out, " } else {\n"); + fprintf(out, " event << \"\";\n"); + fprintf(out, " }\n"); + } else { + fprintf(out, " event << %s[i];\n", chainField.name.c_str()); + } + } + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + fprintf(out, " event.end();\n\n"); + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, " event.begin();\n\n"); + fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + + fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + + fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + + fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + + fprintf(out, " event.end();\n\n"); + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, + " event.AppendCharArray(arg%d.arg, " + "arg%d.arg_length);\n", + argIndex, argIndex); + } else { + if (*arg == JAVA_TYPE_STRING) { + fprintf(out, " if (arg%d == NULL) {\n", argIndex); + fprintf(out, " arg%d = \"\";\n", argIndex); + fprintf(out, " }\n"); + } + fprintf(out, " event << arg%d;\n", argIndex); + } + argIndex++; + } + + fprintf(out, " return event.write(LOG_ID_STATS);\n"); + fprintf(out, " } else {\n"); + fprintf(out, " return 1;\n"); + fprintf(out, " }\n"); + fprintf(out, "}\n"); + fprintf(out, "\n"); + } + +} + +void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName) { + for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); + signature_to_modules_it != atoms.signatures_to_modules.end(); + signature_to_modules_it++) { + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_to_modules_it->first; + + write_native_method_signature(out, methodName, signature, attributionDecl, " {"); + + write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName); + fprintf(out, "}\n\n"); + } +} + +void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName, + const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName, + const string& tryMethodName) { + for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); + signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { + if (!signature_needed_for_module(signature_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_it->first; + + write_native_method_signature(out, methodName, signature, attributionDecl, " {"); + + write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName); + fprintf(out, "}\n\n"); + } +} + +void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName) { + for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); + signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { + if (!signature_needed_for_module(signature_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_it->first; + + write_native_method_signature(out, "static int try_stats_write_non_chained", signature, + attributionDecl, " {"); + + int argIndex = 1; + fprintf(out, " if (kStatsdEnabled) {\n"); + fprintf(out, " stats_event_list event(kStatsEventTag);\n"); + fprintf(out, " event << get_elapsed_realtime_ns();\n\n"); + fprintf(out, " event << code;\n\n"); + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (argIndex == 1) { + fprintf(out, " event.begin();\n\n"); + fprintf(out, " event.begin();\n"); + } + if (*arg == JAVA_TYPE_STRING) { + fprintf(out, " if (arg%d == NULL) {\n", argIndex); + fprintf(out, " arg%d = \"\";\n", argIndex); + fprintf(out, " }\n"); + } + if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, + " event.AppendCharArray(arg%d.arg, " + "arg%d.arg_length);\n", + argIndex, argIndex); + } else { + fprintf(out, " event << arg%d;\n", argIndex); + } + if (argIndex == 2) { + fprintf(out, " event.end();\n\n"); + fprintf(out, " event.end();\n\n"); + } + argIndex++; + } + + fprintf(out, " return event.write(LOG_ID_STATS);\n"); + fprintf(out, " } else {\n"); + fprintf(out, " return 1;\n"); + fprintf(out, " }\n"); + fprintf(out, "}\n"); + fprintf(out, "\n"); + } +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/native_writer_q.h b/tools/stats_log_api_gen/native_writer_q.h new file mode 100644 index 000000000000..a2ab1ae5d5e2 --- /dev/null +++ b/tools/stats_log_api_gen/native_writer_q.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +void write_native_cpp_includes_q(FILE* out); + +void write_native_stats_log_cpp_globals_q(FILE* out); + +void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName); + +void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName); + +void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName); + +void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName, + const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName, + const string& tryMethodName); + +void write_native_get_timestamp_ns_q(FILE* out); + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp new file mode 100644 index 000000000000..5b830eef0603 --- /dev/null +++ b/tools/stats_log_api_gen/utils.cpp @@ -0,0 +1,487 @@ +/* + * 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 "utils.h" + +#include "android-base/strings.h" + +namespace android { +namespace stats_log_api_gen { + +static void build_non_chained_decl_map(const Atoms& atoms, + std::map<int, set<AtomDecl>::const_iterator>* decl_map) { + for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin(); + atom != atoms.non_chained_decls.end(); atom++) { + decl_map->insert(std::make_pair(atom->code, atom)); + } +} + +/** + * Turn lower and camel case into upper case with underscores. + */ +string make_constant_name(const string& str) { + string result; + const int N = str.size(); + bool underscore_next = false; + for (int i=0; i<N; i++) { + char c = str[i]; + if (c >= 'A' && c <= 'Z') { + if (underscore_next) { + result += '_'; + underscore_next = false; + } + } else if (c >= 'a' && c <= 'z') { + c = 'A' + c - 'a'; + underscore_next = true; + } else if (c == '_') { + underscore_next = false; + } + result += c; + } + return result; +} + +const char* cpp_type_name(java_type_t type) { + switch (type) { + case JAVA_TYPE_BOOLEAN: + return "bool"; + case JAVA_TYPE_INT: + case JAVA_TYPE_ENUM: + return "int32_t"; + case JAVA_TYPE_LONG: + return "int64_t"; + case JAVA_TYPE_FLOAT: + return "float"; + case JAVA_TYPE_DOUBLE: + return "double"; + case JAVA_TYPE_STRING: + return "char const*"; + case JAVA_TYPE_BYTE_ARRAY: + return "const BytesField&"; + default: + return "UNKNOWN"; + } +} + +const char* java_type_name(java_type_t type) { + switch (type) { + case JAVA_TYPE_BOOLEAN: + return "boolean"; + case JAVA_TYPE_INT: + case JAVA_TYPE_ENUM: + return "int"; + case JAVA_TYPE_LONG: + return "long"; + case JAVA_TYPE_FLOAT: + return "float"; + case JAVA_TYPE_DOUBLE: + return "double"; + case JAVA_TYPE_STRING: + return "java.lang.String"; + case JAVA_TYPE_BYTE_ARRAY: + return "byte[]"; + default: + return "UNKNOWN"; + } +} + +bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) { + if (moduleName == DEFAULT_MODULE_NAME) { + return true; + } + return atomDecl.hasModule && (moduleName == atomDecl.moduleName); +} + +bool signature_needed_for_module(const set<string>& modules, const string& moduleName) { + if (moduleName == DEFAULT_MODULE_NAME) { + return true; + } + return modules.find(moduleName) != modules.end(); +} + +// Native +// Writes namespaces for the cpp and header files, returning the number of namespaces written. +void write_namespace(FILE* out, const string& cppNamespaces) { + vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); + for (string cppNamespace : cppNamespaceVec) { + fprintf(out, "namespace %s {\n", cppNamespace.c_str()); + } +} + +// Writes namespace closing brackets for cpp and header files. +void write_closing_namespace(FILE* out, const string& cppNamespaces) { + vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); + for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) { + fprintf(out, "} // namespace %s\n", it->c_str()); + } +} + +static void write_cpp_usage( + FILE* out, const string& method_name, const string& atom_code_name, + const AtomDecl& atom, const AtomDecl &attributionDecl) { + fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), + atom_code_name.c_str()); + + for (vector<AtomField>::const_iterator field = atom.fields.begin(); + field != atom.fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (auto chainField : attributionDecl.fields) { + if (chainField.javaType == JAVA_TYPE_STRING) { + fprintf(out, ", const std::vector<%s>& %s", + cpp_type_name(chainField.javaType), + chainField.name.c_str()); + } else { + fprintf(out, ", const %s* %s, size_t %s_length", + cpp_type_name(chainField.javaType), + chainField.name.c_str(), chainField.name.c_str()); + } + } + } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", const std::map<int, int32_t>& %s_int" + ", const std::map<int, int64_t>& %s_long" + ", const std::map<int, char const*>& %s_str" + ", const std::map<int, float>& %s_float", + field->name.c_str(), + field->name.c_str(), + field->name.c_str(), + field->name.c_str()); + } else { + fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str()); + } + } + fprintf(out, ");\n"); +} + +void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, + const string& moduleName) { + fprintf(out, "/**\n"); + fprintf(out, " * Constants for atom codes.\n"); + fprintf(out, " */\n"); + fprintf(out, "enum {\n"); + + std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map; + build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); + + size_t i = 0; + // Print atom constants + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + // Skip if the atom is not needed for the module. + if (!atom_needed_for_module(*atom, moduleName)) { + continue; + } + string constant = make_constant_name(atom->name); + fprintf(out, "\n"); + fprintf(out, " /**\n"); + fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str()); + write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl); + + auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); + if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { + write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second, + attributionDecl); + } + fprintf(out, " */\n"); + char const* const comma = (i == atoms.decls.size() - 1) ? "" : ","; + fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma); + i++; + } + fprintf(out, "\n"); + fprintf(out, "};\n"); + fprintf(out, "\n"); +} + +void write_native_method_signature(FILE* out, const string& methodName, + const vector<java_type_t>& signature, const AtomDecl& attributionDecl, + const string& closer) { + fprintf(out, "%s(int32_t code", methodName.c_str()); + int argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (auto chainField : attributionDecl.fields) { + if (chainField.javaType == JAVA_TYPE_STRING) { + fprintf(out, ", const std::vector<%s>& %s", + cpp_type_name(chainField.javaType), + chainField.name.c_str()); + } else { + fprintf(out, ", const %s* %s, size_t %s_length", + cpp_type_name(chainField.javaType), + chainField.name.c_str(), chainField.name.c_str()); + } + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " + "const std::map<int, int64_t>& arg%d_2, " + "const std::map<int, char const*>& arg%d_3, " + "const std::map<int, float>& arg%d_4", + argIndex, argIndex, argIndex, argIndex); + } else { + fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ")%s\n", closer.c_str()); +} + +void write_native_method_call(FILE* out, const string& methodName, + const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex) { + fprintf(out, "%s(code", methodName.c_str()); + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (auto chainField : attributionDecl.fields) { + if (chainField.javaType == JAVA_TYPE_STRING) { + fprintf(out, ", %s", + chainField.name.c_str()); + } else { + fprintf(out, ", %s, %s_length", + chainField.name.c_str(), chainField.name.c_str()); + } + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, + argIndex, argIndex, argIndex); + } else { + fprintf(out, ", arg%d", argIndex); + } + argIndex++; + } + fprintf(out, ");\n"); +} + +// Java +void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) { + fprintf(out, " // Constants for atom codes.\n"); + + std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map; + build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); + + // Print constants for the atom codes. + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + // Skip if the atom is not needed for the module. + if (!atom_needed_for_module(*atom, moduleName)) { + continue; + } + string constant = make_constant_name(atom->name); + fprintf(out, "\n"); + fprintf(out, " /**\n"); + fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str()); + write_java_usage(out, "write", constant, *atom); + auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); + if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { + write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second); + } + if (moduleName == DEFAULT_MODULE_NAME) { + fprintf(out, " * @hide\n"); + } + fprintf(out, " */\n"); + fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code); + } + fprintf(out, "\n"); +} + +void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName) { + fprintf(out, " // Constants for enum values.\n\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + // Skip if the atom is not needed for the module. + if (!atom_needed_for_module(*atom, moduleName)) { + continue; + } + for (vector<AtomField>::const_iterator field = atom->fields.begin(); + field != atom->fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ENUM) { + fprintf(out, " // Values for %s.%s\n", atom->message.c_str(), + field->name.c_str()); + for (map<int, string>::const_iterator value = field->enumValues.begin(); + value != field->enumValues.end(); value++) { + if (moduleName == DEFAULT_MODULE_NAME) { + fprintf(out, " /** @hide */\n"); + } + fprintf(out, " public static final int %s__%s__%s = %d;\n", + make_constant_name(atom->message).c_str(), + make_constant_name(field->name).c_str(), + make_constant_name(value->second).c_str(), + value->first); + } + fprintf(out, "\n"); + } + } + } +} + +void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, + const AtomDecl& atom) { + fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", + method_name.c_str(), atom_code_name.c_str()); + for (vector<AtomField>::const_iterator field = atom.fields.begin(); + field != atom.fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { + fprintf(out, ", android.os.WorkSource workSource"); + } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", SparseArray<Object> value_map"); + } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", byte[] %s", field->name.c_str()); + } else { + fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str()); + } + } + fprintf(out, ");<br>\n"); +} + +int write_java_non_chained_methods( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const string& moduleName + ) { + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + // Skip if this signature is not needed for the module. + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + + // Print method signature. + if (DEFAULT_MODULE_NAME == moduleName) { + fprintf(out, " /** @hide */\n"); + } + fprintf(out, " public static void write_non_chained(int code"); + vector<java_type_t> signature = signature_to_modules_it->first; + int argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + // Non chained signatures should not have attribution chains. + return 1; + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + // Module logging does not yet support key value pair. + return 1; + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ") {\n"); + + fprintf(out, " write(code"); + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + // First two args are uid and tag of attribution chain. + if (argIndex == 1) { + fprintf(out, ", new int[] {arg%d}", argIndex); + } else if (argIndex == 2) { + fprintf(out, ", new java.lang.String[] {arg%d}", argIndex); + } else { + fprintf(out, ", arg%d", argIndex); + } + argIndex++; + } + fprintf(out, ");\n"); + fprintf(out, " }\n"); + fprintf(out, "\n"); + } + return 0; +} + +int write_java_work_source_methods( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const string& moduleName + ) { + fprintf(out, " // WorkSource methods.\n"); + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + // Skip if this signature is not needed for the module. + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_to_modules_it->first; + // Determine if there is Attribution in this signature. + int attributionArg = -1; + int argIndexMax = 0; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + argIndexMax++; + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + if (attributionArg > -1) { + fprintf(stderr, "An atom contains multiple AttributionNode fields.\n"); + fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n"); + fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n"); + return 1; + } + attributionArg = argIndexMax; + } + } + if (attributionArg < 0) { + continue; + } + + fprintf(out, "\n"); + // Method header (signature) + if (DEFAULT_MODULE_NAME == moduleName) { + fprintf(out, " /** @hide */\n"); + } + fprintf(out, " public static void write(int code"); + int argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + fprintf(out, ", WorkSource ws"); + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ") {\n"); + + // write_non_chained() component. TODO: Remove when flat uids are no longer needed. + fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n"); + fprintf(out, " write_non_chained(code"); + for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { + if (argIndex == attributionArg) { + fprintf(out, ", ws.get(i), ws.getName(i)"); + } else { + fprintf(out, ", arg%d", argIndex); + } + } + fprintf(out, ");\n"); + fprintf(out, " }\n"); // close for-loop + + // write() component. + fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n"); + fprintf(out, " if (workChains != null) {\n"); + fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n"); + fprintf(out, " write(code"); + for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { + if (argIndex == attributionArg) { + fprintf(out, ", wc.getUids(), wc.getTags()"); + } else { + fprintf(out, ", arg%d", argIndex); + } + } + fprintf(out, ");\n"); + fprintf(out, " }\n"); // close for-loop + fprintf(out, " }\n"); // close if + fprintf(out, " }\n"); // close method + } + return 0; +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h new file mode 100644 index 000000000000..50737a68bf89 --- /dev/null +++ b/tools/stats_log_api_gen/utils.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <map> +#include <set> +#include <vector> + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +const string DEFAULT_MODULE_NAME = "DEFAULT"; +const string DEFAULT_CPP_NAMESPACE = "android,util"; +const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h"; +const string DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT = "atoms_info.h"; +const string DEFAULT_JAVA_PACKAGE = "android.util"; +const string DEFAULT_JAVA_CLASS = "StatsLogInternal"; + +const int JAVA_MODULE_REQUIRES_FLOAT = 0x01; +const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02; + +string make_constant_name(const string& str); + +const char* cpp_type_name(java_type_t type); + +const char* java_type_name(java_type_t type); + +bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName); + +bool signature_needed_for_module(const set<string>& modules, const string& moduleName); + +// Common Native helpers +void write_namespace(FILE* out, const string& cppNamespaces); + +void write_closing_namespace(FILE* out, const string& cppNamespaces); + +void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, + const string& moduleName); + +void write_native_method_signature(FILE* out, const string& methodName, + const vector<java_type_t>& signature, const AtomDecl& attributionDecl, + const string& closer); + +void write_native_method_call(FILE* out, const string& methodName, + const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex = 1); + +// Common Java helpers. +void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName); + +void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName); + +void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, + const AtomDecl& atom); + +int write_java_non_chained_methods(FILE* out, const map<vector<java_type_t>, + set<string>>& signatures_to_modules, + const string& moduleName); + +int write_java_work_source_methods( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const string& moduleName); + +} // namespace stats_log_api_gen +} // namespace android diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index c0c0361dd92f..2901bd8cbb48 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -17,7 +17,7 @@ package android.net.wifi; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index ed416429a279..933dded815b9 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -19,7 +19,7 @@ package android.net.wifi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.PackageManager; import android.net.IpConfiguration; import android.net.IpConfiguration.ProxySettings; diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 9d4b837ce2d1..a9c2eb57291a 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -16,7 +16,7 @@ package android.net.wifi; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.security.Credentials; diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 0b557942c87b..8bad71ba747b 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -19,7 +19,7 @@ package android.net.wifi; import android.annotation.IntRange; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; import android.os.Build; diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 671b3c715012..f85bb5f8ad59 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -29,8 +29,8 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ParceledListSlice; import android.net.ConnectivityManager; diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java index f187e1042c58..a591f312028e 100644 --- a/wifi/java/android/net/wifi/WifiSsid.java +++ b/wifi/java/android/net/wifi/WifiSsid.java @@ -16,7 +16,7 @@ package android.net.wifi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java index c3cfb0266328..b0ea7202b7ba 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java @@ -19,7 +19,7 @@ package android.net.wifi.p2p; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.MacAddress; import android.net.wifi.WpsInfo; import android.os.Parcel; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java index c5318a9e275a..69aefcce4f5b 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java @@ -16,7 +16,7 @@ package android.net.wifi.p2p; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java index acf06fbac681..ededf67fec7f 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java @@ -16,10 +16,9 @@ package android.net.wifi.p2p; -import android.annotation.UnsupportedAppUsage; -import android.os.Parcelable; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; -import android.net.wifi.p2p.WifiP2pDevice; +import android.os.Parcelable; import android.text.TextUtils; import java.util.ArrayList; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java index 4866bd4b2ce9..b292da193a89 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java @@ -16,7 +16,7 @@ package android.net.wifi.p2p; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java index 62524d9c2bd6..6068d3a2f697 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java @@ -15,14 +15,14 @@ */ package android.net.wifi.p2p; -import java.util.Collection; -import java.util.Map; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.LruCache; +import java.util.Collection; +import java.util.Map; + /** * A class representing a Wi-Fi P2p group list diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index d37c4a2e78db..eec4a0007d8e 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -23,7 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.NetworkInfo; import android.net.wifi.WpsInfo; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java b/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java index 153e03cc4d9d..d0fe92d5249d 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pProvDiscEvent.java @@ -16,7 +16,7 @@ package android.net.wifi.p2p; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A class representing a Wi-Fi p2p provisional discovery request/response diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java index 3caa280ef62a..7a5f909f93ae 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java @@ -16,10 +16,10 @@ package android.net.wifi.p2p; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; import java.util.Locale; diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java index e32c8e80ad1c..0de7ba6439eb 100644 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java @@ -16,7 +16,7 @@ package android.net.wifi.p2p.nsd; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.nsd.DnsSdTxtRecord; import android.os.Build; import android.text.TextUtils; diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java index db0bdb81fef3..37b442baeb3f 100644 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java @@ -16,7 +16,7 @@ package android.net.wifi.p2p.nsd; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java index 87528c4180af..68cbb88037b0 100644 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java @@ -16,7 +16,7 @@ package android.net.wifi.p2p.nsd; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.wifi.p2p.WifiP2pManager; import android.os.Build; import android.os.Parcel; |