diff options
135 files changed, 2055 insertions, 949 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 451175f62183..45f65709533f 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -15,6 +15,7 @@ aconfig_srcjars = [ ":android.content.pm.flags-aconfig-java{.generated_srcjars}", ":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}", + ":android.net.vcn.flags-aconfig-java{.generated_srcjars}", ":android.nfc.flags-aconfig-java{.generated_srcjars}", ":android.os.flags-aconfig-java{.generated_srcjars}", ":android.security.flags-aconfig-java{.generated_srcjars}", @@ -197,3 +198,34 @@ java_aconfig_library { aconfig_declarations: "com.android.net.flags-aconfig", defaults: ["framework-minus-apex-aconfig-java-defaults"], } + +// Media +aconfig_declarations { + name: "android.media.playback.flags-aconfig", + package: "com.android.media.playback.flags", + srcs: ["media/jni/playback_flags.aconfig"], +} + +cc_aconfig_library { + name: "android.media.playback.flags-aconfig-cc", + aconfig_declarations: "android.media.playback.flags-aconfig", +} + +java_aconfig_library { + name: "android.media.playback.flags-aconfig-java", + aconfig_declarations: "android.media.playback.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + +// VCN +aconfig_declarations { + name: "android.net.vcn.flags-aconfig", + package: "android.net.vcn", + srcs: ["core/java/android/net/vcn/*.aconfig"], +} + +java_aconfig_library { + name: "android.net.vcn.flags-aconfig-java", + aconfig_declarations: "android.net.vcn.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/Android.bp b/Android.bp index ccff26fb70d2..1fb50b6c24a6 100644 --- a/Android.bp +++ b/Android.bp @@ -321,7 +321,6 @@ java_defaults { ":installd_aidl", ":libaudioclient_aidl", ":libbinder_aidl", - ":libbluetooth-binder-aidl", ":libcamera_client_aidl", ":libcamera_client_framework_aidl", ":libupdate_engine_aidl", @@ -370,17 +369,12 @@ java_defaults { // TODO(b/120066492): remove default_television.xml when the build system // propagates "required" properly. "default_television.xml", - "framework-platform-compat-config", // TODO(b/120066492): remove gps_debug and protolog.conf.json when the build // system propagates "required" properly. "gps_debug.conf", - "icu4j-platform-compat-config", "protolog.conf.json.gz", - "services-platform-compat-config", - "TeleService-platform-compat-config", - "documents-ui-compat-config", - "calendar-provider-compat-config", - "contacts-provider-platform-compat-config", + // any install dependencies should go into framework-minus-apex-install-dependencies + // rather than here to avoid bloating incremental build time ], libs: [ "androidx.annotation_annotation", @@ -415,21 +409,18 @@ java_defaults { ], } -java_library { - name: "framework-minus-apex", +// Separated so framework-minus-apex-defaults can be used without the libs dependency +java_defaults { + name: "framework-minus-apex-with-libs-defaults", defaults: ["framework-minus-apex-defaults"], - installable: true, - // For backwards compatibility. - stem: "framework", - apex_available: ["//apex_available:platform"], - visibility: [ - "//frameworks/base", - // TODO(b/147128803) remove the below lines - "//frameworks/base/apex/blobstore/framework", - "//frameworks/base/apex/jobscheduler/framework", - "//frameworks/base/packages/Tethering/tests/unit", - "//packages/modules/Connectivity/Tethering/tests/unit", + libs: [ + "framework-virtualization.stubs.module_lib", + "framework-location.impl", ], +} + +java_defaults { + name: "framework-non-updatable-lint-defaults", lint: { extra_check_modules: ["AndroidFrameworkLintChecker"], disabled_checks: ["ApiMightLeakAppVisibility"], @@ -443,6 +434,43 @@ java_library { "UseOfCallerAwareMethodsWithClearedIdentity", ], }, +} + +// we are unfortunately building the turbine jar twice, but more efficient and less complex +// than generating a similar set of stubs with metalava +java_library { + name: "framework-minus-apex-headers", + defaults: ["framework-minus-apex-defaults"], + installable: false, + // For backwards compatibility. + stem: "framework", + apex_available: ["//apex_available:platform"], + visibility: [ + "//frameworks/base/location", + ], + compile_dex: false, + headers_only: true, +} + +java_library { + name: "framework-minus-apex", + defaults: [ + "framework-minus-apex-with-libs-defaults", + "framework-non-updatable-lint-defaults", + ], + installable: true, + // For backwards compatibility. + stem: "framework", + apex_available: ["//apex_available:platform"], + visibility: [ + "//frameworks/base", + "//frameworks/base/location", + // TODO(b/147128803) remove the below lines + "//frameworks/base/apex/blobstore/framework", + "//frameworks/base/apex/jobscheduler/framework", + "//frameworks/base/packages/Tethering/tests/unit", + "//packages/modules/Connectivity/Tethering/tests/unit", + ], errorprone: { javacflags: [ "-Xep:AndroidFrameworkCompatChange:ERROR", @@ -453,7 +481,7 @@ java_library { java_library { name: "framework-minus-apex-intdefs", - defaults: ["framework-minus-apex-defaults"], + defaults: ["framework-minus-apex-with-libs-defaults"], plugins: ["intdef-annotation-processor"], // Errorprone and android lint will already run on framework-minus-apex, don't rerun them on @@ -481,6 +509,7 @@ java_library { installable: false, // this lib is a build-only library static_libs: [ "app-compat-annotations", + "framework-location.impl", "framework-minus-apex", "framework-updatable-stubs-module_libs_api", ], @@ -488,6 +517,20 @@ java_library { apex_available: ["//apex_available:platform"], } +java_library { + name: "framework-minus-apex-install-dependencies", + required: [ + "framework-minus-apex", + "framework-platform-compat-config", + "services-platform-compat-config", + "icu4j-platform-compat-config", + "TeleService-platform-compat-config", + "documents-ui-compat-config", + "calendar-provider-compat-config", + "contacts-provider-platform-compat-config", + ], +} + platform_compat_config { name: "framework-platform-compat-config", src: ":framework-minus-apex", @@ -560,46 +603,11 @@ java_library { ], } -// TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp -metalava_framework_docs_args = "" + - "--api-lint-ignore-prefix android.icu. " + - "--api-lint-ignore-prefix java. " + - "--api-lint-ignore-prefix junit. " + - "--api-lint-ignore-prefix org. " + - "--error NoSettingsProvider " + - "--error UnhiddenSystemApi " + - "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " + - "--hide BroadcastBehavior " + - "--hide CallbackInterface " + - "--hide DeprecationMismatch " + - "--hide HiddenSuperclass " + - "--hide HiddenTypeParameter " + - "--hide MissingPermission " + - "--hide-package android.audio.policy.configuration.V7_0 " + - "--hide-package com.android.server " + - "--hide RequiresPermission " + - "--hide SdkConstant " + - "--hide Todo " + - "--hide UnavailableSymbol " + - "--manifest $(location :frameworks-base-core-AndroidManifest.xml) " - -packages_to_document = [ - "android", - "dalvik", - "java", - "javax", - "junit", - "org.apache.http", - "org.json", - "org.w3c.dom", - "org.xml.sax", - "org.xmlpull", -] - filegroup { name: "android-non-updatable-stub-sources", srcs: [ ":framework-mime-sources", // mimemap builds separately but has no separate droidstubs. + ":framework-minus-apex-aconfig-srcjars", ":framework-non-updatable-sources", ":opt-telephony-srcs", ":opt-net-voip-srcs", @@ -609,86 +617,6 @@ filegroup { visibility: ["//frameworks/base/api"], } -// Defaults for all stubs that include the non-updatable framework. These defaults do not include -// module symbols, so will not compile correctly on their own. Users must add module APIs to the -// classpath (or sources) somehow. -stubs_defaults { - name: "android-non-updatable-stubs-defaults", - srcs: [":android-non-updatable-stub-sources"], - sdk_version: "none", - system_modules: "none", - java_version: "1.8", - arg_files: [":frameworks-base-core-AndroidManifest.xml"], - aidl: { - include_dirs: [ - "frameworks/av/aidl", - "frameworks/base/media/aidl", - "frameworks/base/telephony/java", - "frameworks/native/libs/permission/aidl", - "packages/modules/Bluetooth/framework/aidl-export", - "packages/modules/Connectivity/framework/aidl-export", - "packages/modules/Media/apex/aidl/stable", - "hardware/interfaces/biometrics/common/aidl", - "hardware/interfaces/biometrics/fingerprint/aidl", - "hardware/interfaces/graphics/common/aidl", - "hardware/interfaces/keymaster/aidl", - "system/hardware/interfaces/media/aidl", - ], - }, - // These are libs from framework-internal-utils that are required (i.e. being referenced) - // from framework-non-updatable-sources. Add more here when there's a need. - // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular - // dependencies gets bigger. - libs: [ - "android.hardware.cas-V1.2-java", - "android.hardware.health-V1.0-java-constants", - "android.hardware.radio-V1.5-java", - "android.hardware.radio-V1.6-java", - "android.hardware.thermal-V1.0-java-constants", - "android.hardware.thermal-V2.0-java", - "android.hardware.tv.input-V1.0-java-constants", - "android.hardware.usb-V1.0-java-constants", - "android.hardware.usb-V1.1-java-constants", - "android.hardware.usb.gadget-V1.0-java", - "android.hardware.vibrator-V1.3-java", - "framework-protos", - ], - filter_packages: packages_to_document, - high_mem: true, // Lots of sources => high memory use, see b/170701554 - installable: false, - annotations_enabled: true, - previous_api: ":android.api.public.latest", - merge_annotations_dirs: ["metalava-manual"], - defaults_visibility: ["//frameworks/base/api"], - visibility: ["//frameworks/base/api"], -} - -// Defaults with module APIs in the classpath (mostly from prebuilts). -// Suitable for compiling android-non-updatable. -stubs_defaults { - name: "module-classpath-stubs-defaults", - aidl: { - include_dirs: [ - "packages/modules/Bluetooth/framework/aidl-export", - "packages/modules/Connectivity/framework/aidl-export", - "packages/modules/Media/apex/aidl/stable", - ], - }, - libs: [ - "art.module.public.api", - "sdk_module-lib_current_framework-tethering", - "sdk_module-lib_current_framework-connectivity-t", - "sdk_public_current_framework-bluetooth", - // There are a few classes from modules used by the core that - // need to be resolved by metalava. We use a prebuilt stub of the - // full sdk to ensure we can resolve them. If a new class gets added, - // the prebuilts/sdk/current needs to be updated. - "sdk_system_current_android", - // NOTE: The below can be removed once the prebuilt stub contains IKE. - "sdk_system_current_android.net.ipsec.ike", - ], -} - build = [ "AconfigFlags.bp", "ProtoLibraries.bp", diff --git a/BAL_OWNERS b/BAL_OWNERS new file mode 100644 index 000000000000..d56a1d4634df --- /dev/null +++ b/BAL_OWNERS @@ -0,0 +1,5 @@ +brufino@google.com +achim@google.com +topjohnwu@google.com +lus@google.com + diff --git a/api/Android.bp b/api/Android.bp index e9cc40513221..d2e0849ed946 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -87,6 +87,7 @@ combined_apis { "framework-devicelock", "framework-graphics", "framework-healthfitness", + "framework-location", "framework-media", "framework-mediaprovider", "framework-ondevicepersonalization", @@ -261,6 +262,157 @@ java_genrule { cmd: "cat $(in) | md5sum | cut -d' ' -f1 > $(out)", } +packages_to_document = [ + "android", + "dalvik", + "java", + "javax", + "junit", + "org.apache.http", + "org.json", + "org.w3c.dom", + "org.xml.sax", + "org.xmlpull", +] + +// Defaults for all stubs that include the non-updatable framework. These defaults do not include +// module symbols, so will not compile correctly on their own. Users must add module APIs to the +// classpath (or sources) somehow. +stubs_defaults { + name: "android-non-updatable-stubs-defaults", + srcs: [":android-non-updatable-stub-sources"], + sdk_version: "none", + system_modules: "none", + java_version: "1.8", + arg_files: [":frameworks-base-core-AndroidManifest.xml"], + aidl: { + include_dirs: [ + "frameworks/av/aidl", + "frameworks/base/media/aidl", + "frameworks/base/telephony/java", + "frameworks/native/libs/permission/aidl", + "packages/modules/Bluetooth/framework/aidl-export", + "packages/modules/Connectivity/framework/aidl-export", + "packages/modules/Media/apex/aidl/stable", + "hardware/interfaces/biometrics/common/aidl", + "hardware/interfaces/biometrics/fingerprint/aidl", + "hardware/interfaces/graphics/common/aidl", + "hardware/interfaces/keymaster/aidl", + "system/hardware/interfaces/media/aidl", + ], + }, + // These are libs from framework-internal-utils that are required (i.e. being referenced) + // from framework-non-updatable-sources. Add more here when there's a need. + // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular + // dependencies gets bigger. + libs: [ + "android.hardware.cas-V1.2-java", + "android.hardware.health-V1.0-java-constants", + "android.hardware.radio-V1.5-java", + "android.hardware.radio-V1.6-java", + "android.hardware.thermal-V1.0-java-constants", + "android.hardware.thermal-V2.0-java", + "android.hardware.tv.input-V1.0-java-constants", + "android.hardware.usb-V1.0-java-constants", + "android.hardware.usb-V1.1-java-constants", + "android.hardware.usb.gadget-V1.0-java", + "android.hardware.vibrator-V1.3-java", + "framework-protos", + ], + flags: [ + "--api-lint-ignore-prefix android.icu.", + "--api-lint-ignore-prefix java.", + "--api-lint-ignore-prefix junit.", + "--api-lint-ignore-prefix org.", + "--error NoSettingsProvider", + "--error UnhiddenSystemApi", + "--error UnflaggedApi", + "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*", + "--hide BroadcastBehavior", + "--hide CallbackInterface", + "--hide DeprecationMismatch", + "--hide HiddenSuperclass", + "--hide MissingPermission", + "--hide RequiresPermission", + "--hide SdkConstant", + "--hide Todo", + "--hide-package android.audio.policy.configuration.V7_0", + "--hide-package com.android.server", + "--manifest $(location :frameworks-base-core-AndroidManifest.xml)", + ], + filter_packages: packages_to_document, + high_mem: true, // Lots of sources => high memory use, see b/170701554 + installable: false, + annotations_enabled: true, + previous_api: ":android.api.public.latest", + merge_annotations_dirs: ["metalava-manual"], + defaults_visibility: ["//frameworks/base/api"], + visibility: ["//frameworks/base/api"], +} + +// Defaults with module APIs in the classpath (mostly from prebuilts). +// Suitable for compiling android-non-updatable. +stubs_defaults { + name: "module-classpath-stubs-defaults", + aidl: { + include_dirs: [ + "packages/modules/Bluetooth/framework/aidl-export", + "packages/modules/Connectivity/framework/aidl-export", + "packages/modules/Media/apex/aidl/stable", + ], + }, + libs: [ + "art.module.public.api", + "sdk_module-lib_current_framework-tethering", + "sdk_module-lib_current_framework-connectivity-t", + "sdk_public_current_framework-bluetooth", + // There are a few classes from modules used by the core that + // need to be resolved by metalava. We use a prebuilt stub of the + // full sdk to ensure we can resolve them. If a new class gets added, + // the prebuilts/sdk/current needs to be updated. + "sdk_system_current_android", + // NOTE: The below can be removed once the prebuilt stub contains IKE. + "sdk_system_current_android.net.ipsec.ike", + ], +} + +// Defaults for the java_sdk_libraries of unbundled jars from framework. +// java_sdk_libraries using these defaults should also add themselves to the +// non_updatable_modules list in frameworks/base/api/api.go +java_defaults { + name: "framework-non-updatable-unbundled-defaults", + defaults: [ + "framework-non-updatable-lint-defaults", + "non-updatable-framework-module-defaults", + ], + public: { + libs: ["android_module_lib_stubs_current"], + }, + system: { + libs: ["android_module_lib_stubs_current"], + }, + module_lib: { + libs: ["android_module_lib_stubs_current"], + }, + test: { + libs: ["android_test_frameworks_core_stubs_current"], + }, + sdk_version: "core_platform", + stub_only_libs: ["framework-protos"], + impl_only_libs: ["framework-minus-apex-headers"], // the framework, including hidden API + impl_library_visibility: ["//frameworks/base"], + defaults_visibility: ["//frameworks/base/location"], + plugins: ["error_prone_android_framework"], + errorprone: { + javacflags: [ + "-Xep:AndroidFrameworkCompatChange:ERROR", + "-Xep:AndroidFrameworkUid:ERROR", + ], + }, + // Include manual annotations in API txt files + merge_annotations_dirs: ["metalava-manual"], +} + build = [ "ApiDocs.bp", "StubLibraries.bp", diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp index e086bfe5cbb2..5744bdfd4b28 100644 --- a/api/ApiDocs.bp +++ b/api/ApiDocs.bp @@ -72,7 +72,6 @@ droidstubs { "android-non-updatable-doc-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args, } droidstubs { @@ -81,8 +80,7 @@ droidstubs { "android-non-updatable-doc-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args + - " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ", + flags: ["--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"], } droidstubs { @@ -91,9 +89,10 @@ droidstubs { "android-non-updatable-doc-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args + - " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) " + - " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\) ", + flags: [ + "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)", + "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)", + ], generate_stubs: false, // We're only using this module for the annotations.zip output, disable doc-stubs. write_sdk_values: false, } @@ -104,10 +103,11 @@ droidstubs { "android-non-updatable-doc-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args + - " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) " + - " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\) " + - " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ", + flags: [ + "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)", + "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)", + "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\)", + ], generate_stubs: false, // We're only using this module for the annotations.zip output, disable doc-stubs. write_sdk_values: false, } @@ -116,7 +116,6 @@ droidstubs { name: "framework-doc-stubs", defaults: ["android-non-updatable-doc-stubs-defaults"], srcs: [":all-modules-public-stubs-source"], - args: metalava_framework_docs_args, api_levels_module: "api_versions_public", aidl: { include_dirs: [ @@ -129,8 +128,7 @@ droidstubs { droidstubs { name: "framework-doc-system-stubs", defaults: ["framework-doc-stubs-sources-default"], - args: metalava_framework_docs_args + - " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ", + flags: ["--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"], api_levels_module: "api_versions_system", } @@ -139,30 +137,6 @@ droidstubs { // using droiddoc ///////////////////////////////////////////////////////////////////// -// doclava contains checks for a few issues that are have been migrated to metalava. -// disable them in doclava, to avoid mistriggering or double triggering. -ignore_doclava_errors_checked_by_metalava = "" + - "-hide 111 " + // HIDDEN_SUPERCLASS - "-hide 113 " + // DEPRECATION_MISMATCH - "-hide 125 " + // REQUIRES_PERMISSION - "-hide 126 " + // BROADCAST_BEHAVIOR - "-hide 127 " + // SDK_CONSTANT - "-hide 128 " // TODO - -framework_docs_only_args = "-android " + - "-manifest $(location :frameworks-base-core-AndroidManifest.xml) " + - "-metalavaApiSince " + - "-werror " + - "-lerror " + - ignore_doclava_errors_checked_by_metalava + - "-overview $(location :frameworks-base-java-overview) " + - // Federate Support Library references against local API file. - "-federate SupportLib https://developer.android.com " + - "-federationapi SupportLib $(location :current-support-api) " + - // Federate Support Library references against local API file. - "-federate AndroidX https://developer.android.com " + - "-federationapi AndroidX $(location :current-androidx-api) " - doc_defaults { name: "framework-docs-default", sdk_version: "none", @@ -182,6 +156,28 @@ doc_defaults { resourcesdir: "docs/html/reference/images/", resourcesoutdir: "reference/android/images/", lint_baseline: "javadoc-lint-baseline", + flags: [ + "-android", + "-manifest $(location :frameworks-base-core-AndroidManifest.xml)", + "-metalavaApiSince", + "-werror", + "-lerror", + "-overview $(location :frameworks-base-java-overview)", + // Federate Support Library references against local API file. + "-federate SupportLib https://developer.android.com", + "-federationapi SupportLib $(location :current-support-api)", + // Federate Support Library references against local API file. + "-federate AndroidX https://developer.android.com", + "-federationapi AndroidX $(location :current-androidx-api)", + // doclava contains checks for a few issues that are have been migrated to metalava. + // disable them in doclava, to avoid mistriggering or double triggering. + "-hide 111", // HIDDEN_SUPERCLASS + "-hide 113", // DEPRECATION_MISMATCH + "-hide 125", // REQUIRES_PERMISSION + "-hide 126", // BROADCAST_BEHAVIOR + "-hide 127", // SDK_CONSTANT + "-hide 128", // TODO + ], hdf: [ "dac true", "sdk.codename O", @@ -217,7 +213,10 @@ droiddoc { ], compat_config: ":global-compat-config", proofread_file: "offline-sdk-docs-proofread.txt", - args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"", + flags: [ + "-offlinemode", + "-title \"Android SDK\"", + ], static_doc_index_redirect: "docs/docs-preview-index.html", } @@ -234,7 +233,11 @@ droiddoc { "android.whichdoc offline", ], proofread_file: "offline-sdk-referenceonly-docs-proofread.txt", - args: framework_docs_only_args + " -offlinemode -title \"Android SDK\" -referenceonly", + flags: [ + "-offlinemode", + "-title \"Android SDK\"", + "-referenceonly", + ], static_doc_index_redirect: "docs/docs-documentation-redirect.html", static_doc_properties: "docs/source.properties", } @@ -252,8 +255,14 @@ droiddoc { "android.whichdoc offline", ], proofread_file: "offline-system-sdk-referenceonly-docs-proofread.txt", - args: framework_docs_only_args + " -hide 101 -hide 104 -hide 108" + - " -offlinemode -title \"Android System SDK\" -referenceonly", + flags: [ + "-hide 101", + "-hide 104", + "-hide 108", + "-offlinemode", + "-title \"Android System SDK\"", + "-referenceonly", + ], static_doc_index_redirect: "docs/docs-documentation-redirect.html", static_doc_properties: "docs/source.properties", } @@ -269,22 +278,28 @@ droiddoc { "android.hasSamples true", ], proofread_file: "ds-docs-proofread.txt", - args: framework_docs_only_args + - " -toroot / -yamlV2 -samplegroup Admin " + - " -samplegroup Background " + - " -samplegroup Connectivity " + - " -samplegroup Content " + - " -samplegroup Input " + - " -samplegroup Media " + - " -samplegroup Notification " + - " -samplegroup RenderScript " + - " -samplegroup Security " + - " -samplegroup Sensors " + - " -samplegroup System " + - " -samplegroup Testing " + - " -samplegroup UI " + - " -samplegroup Views " + - " -samplegroup Wearable -devsite -samplesdir development/samples/browseable ", + flags: [ + " -toroot /", + "-yamlV2", + "-samplegroup Admin", + "-samplegroup Background", + "-samplegroup Connectivity", + "-samplegroup Content", + "-samplegroup Input", + "-samplegroup Media", + "-samplegroup Notification", + "-samplegroup RenderScript", + "-samplegroup Security", + "-samplegroup Sensors", + "-samplegroup System", + "-samplegroup Testing", + "-samplegroup UI", + "-samplegroup Views", + "-samplegroup Wearable", + "-devsite", + "-samplesdir", + "development/samples/browseable", + ], } droiddoc { @@ -292,8 +307,11 @@ droiddoc { srcs: [ ":framework-doc-stubs", ], - args: "-noJdkLink -links https://kotlinlang.org/api/latest/jvm/stdlib/^external/dokka/package-list " + + flags: [ + "-noJdkLink", + "-links https://kotlinlang.org/api/latest/jvm/stdlib/^external/dokka/package-list", "-noStdlibLink", + ], proofread_file: "ds-dokka-proofread.txt", dokka_enabled: true, } @@ -346,11 +364,12 @@ droiddoc { hdf: [ "android.whichdoc online", ], - args: framework_docs_only_args + - " -staticonly " + - " -toroot / " + - " -devsite " + - " -ignoreJdLinks ", + flags: [ + "-staticonly", + "-toroot /", + "-devsite", + "-ignoreJdLinks", + ], } droiddoc { @@ -362,8 +381,9 @@ droiddoc { hdf: [ "android.whichdoc online", ], - args: framework_docs_only_args + - " -toroot / " + - " -atLinksNavtree " + - " -navtreeonly ", + flags: [ + "-toroot /", + "-atLinksNavtree", + "-navtreeonly", + ], } diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp index ada4b1a9cba5..5688b968db87 100644 --- a/api/StubLibraries.bp +++ b/api/StubLibraries.bp @@ -29,14 +29,10 @@ droidstubs { name: "api-stubs-docs-non-updatable", - srcs: [ - ":framework-minus-apex-aconfig-srcjars", - ], defaults: [ "android-non-updatable-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args, check_api: { current: { api_file: ":non-updatable-current.txt", @@ -50,6 +46,7 @@ droidstubs { api_lint: { enabled: true, new_since: ":android.api.public.latest", + baseline_file: ":non-updatable-lint-baseline.txt", }, }, dists: [ @@ -69,30 +66,33 @@ droidstubs { api_surface: "public", } -priv_apps = " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" + - "\\)" +priv_apps = [ + "--show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" + + "\\)", +] -priv_apps_in_stubs = " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" + - "\\)" +priv_apps_in_stubs = [ + "--show-for-stub-purposes-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" + + "\\)", +] -test = " --show-annotation android.annotation.TestApi" +test = ["--show-annotation android.annotation.TestApi"] -module_libs = " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" + - "\\)" +module_libs = [ + "--show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" + + "\\)", +] droidstubs { name: "system-api-stubs-docs-non-updatable", - srcs: [ - ":framework-minus-apex-aconfig-srcjars", - ], defaults: [ "android-non-updatable-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args + priv_apps, + flags: priv_apps, check_api: { current: { api_file: ":non-updatable-system-current.txt", @@ -128,14 +128,11 @@ droidstubs { droidstubs { name: "test-api-stubs-docs-non-updatable", - srcs: [ - ":framework-minus-apex-aconfig-srcjars", - ], defaults: [ "android-non-updatable-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args + test + priv_apps_in_stubs, + flags: test + priv_apps_in_stubs, check_api: { current: { api_file: ":non-updatable-test-current.txt", @@ -143,6 +140,7 @@ droidstubs { }, api_lint: { enabled: true, + new_since: ":android.api.test.latest", baseline_file: ":non-updatable-test-lint-baseline.txt", }, }, @@ -177,14 +175,11 @@ droidstubs { droidstubs { name: "module-lib-api-stubs-docs-non-updatable", - srcs: [ - ":framework-minus-apex-aconfig-srcjars", - ], defaults: [ "android-non-updatable-stubs-defaults", "module-classpath-stubs-defaults", ], - args: metalava_framework_docs_args + priv_apps_in_stubs + module_libs, + flags: priv_apps_in_stubs + module_libs, check_api: { current: { api_file: ":non-updatable-module-lib-current.txt", @@ -521,6 +516,21 @@ java_library { } java_library { + name: "android_test_frameworks_core_stubs_current.from-source", + static_libs: [ + "all-updatable-modules-system-stubs", + "android-non-updatable.stubs.test", + ], + defaults: [ + "android.jar_defaults", + "android_stubs_dists_default", + ], + dist: { + dir: "apistubs/android/test-core", + }, +} + +java_library { name: "android_module_lib_stubs_current.from-source", defaults: [ "android.jar_defaults", @@ -634,6 +644,7 @@ java_defaults { api_surface: "test", api_contributions: [ "framework-virtualization.stubs.source.test.api.contribution", + "framework-location.stubs.source.test.api.contribution", ], } @@ -954,7 +965,7 @@ droidstubs { merge_annotations_dirs: [ "metalava-manual", ], - args: priv_apps, + flags: priv_apps, } java_library { diff --git a/api/api.go b/api/api.go index 692d38fe21a2..8df6dab715ef 100644 --- a/api/api.go +++ b/api/api.go @@ -31,6 +31,7 @@ const art = "art.module.public.api" const conscrypt = "conscrypt.module.public.api" const i18n = "i18n.module.public.api" const virtualization = "framework-virtualization" +const location = "framework-location" var core_libraries_modules = []string{art, conscrypt, i18n} @@ -42,7 +43,7 @@ var core_libraries_modules = []string{art, conscrypt, i18n} // APIs. // In addition, the modules in this list are allowed to contribute to test APIs // stubs. -var non_updatable_modules = []string{virtualization} +var non_updatable_modules = []string{virtualization, location} // The intention behind this soong plugin is to generate a number of "merged" // API-related modules that would otherwise require a large amount of very @@ -296,8 +297,10 @@ func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) { } func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) { - // The user of this module compiles against the "core" SDK, so remove core libraries to avoid dupes. + // The user of this module compiles against the "core" SDK and against non-updatable modules, + // so remove to avoid dupes. modules = removeAll(modules, core_libraries_modules) + modules = removeAll(modules, non_updatable_modules) props := libraryProps{} props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api") props.Static_libs = transformArray(modules, "", ".stubs.module_lib") @@ -393,6 +396,7 @@ func createFullApiLibraries(ctx android.LoadHookContext) { "android_stubs_current", "android_system_stubs_current", "android_test_stubs_current", + "android_test_frameworks_core_stubs_current", "android_module_lib_stubs_current", "android_system_server_stubs_current", } diff --git a/api/gen_combined_removed_dex.sh b/api/gen_combined_removed_dex.sh index 71f366a6aae2..e0153f7c1091 100755 --- a/api/gen_combined_removed_dex.sh +++ b/api/gen_combined_removed_dex.sh @@ -6,6 +6,6 @@ shift 2 # Convert each removed.txt to the "dex format" equivalent, and print all output. for f in "$@"; do - "$metalava_path" "$f" --dex-api "${tmp_dir}/tmp" + "$metalava_path" signature-to-dex "$f" "${tmp_dir}/tmp" cat "${tmp_dir}/tmp" done diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java index 020ca3387555..ee2af129d400 100644 --- a/cmds/svc/src/com/android/commands/svc/NfcCommand.java +++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java @@ -16,10 +16,11 @@ package com.android.commands.svc; +import android.app.ActivityThread; import android.content.Context; -import android.nfc.INfcAdapter; -import android.os.RemoteException; -import android.os.ServiceManager; +import android.nfc.NfcAdapter; +import android.nfc.NfcManager; +import android.os.Looper; public class NfcCommand extends Svc.Command { @@ -42,27 +43,26 @@ public class NfcCommand extends Svc.Command { @Override public void run(String[] args) { - INfcAdapter adapter = INfcAdapter.Stub.asInterface( - ServiceManager.getService(Context.NFC_SERVICE)); - + Looper.prepareMainLooper(); + ActivityThread.initializeMainlineModules(); + Context context = ActivityThread.systemMain().getSystemContext(); + NfcManager nfcManager = context.getSystemService(NfcManager.class); + if (nfcManager == null) { + System.err.println("Got a null NfcManager, is the system running?"); + return; + } + NfcAdapter adapter = nfcManager.getDefaultAdapter(); if (adapter == null) { System.err.println("Got a null NfcAdapter, is the system running?"); return; } - - try { - if (args.length == 2 && "enable".equals(args[1])) { - adapter.enable(); - return; - } else if (args.length == 2 && "disable".equals(args[1])) { - adapter.disable(true); - return; - } - } catch (RemoteException e) { - System.err.println("NFC operation failed: " + e); + if (args.length == 2 && "enable".equals(args[1])) { + adapter.enable(); + return; + } else if (args.length == 2 && "disable".equals(args[1])) { + adapter.disable(true); return; } - System.err.println(longHelp()); } diff --git a/cmds/svc/src/com/android/commands/svc/OWNERS b/cmds/svc/src/com/android/commands/svc/OWNERS new file mode 100644 index 000000000000..d5a5d7b3b858 --- /dev/null +++ b/cmds/svc/src/com/android/commands/svc/OWNERS @@ -0,0 +1,2 @@ +# Bug component: 48448 +per-file NfcCommand.java = file:platform/packages/apps/Nfc:/OWNERS diff --git a/core/api/Android.bp b/core/api/Android.bp index 71a2ca2903f6..907916a125da 100644 --- a/core/api/Android.bp +++ b/core/api/Android.bp @@ -38,6 +38,11 @@ filegroup { } filegroup { + name: "non-updatable-lint-baseline.txt", + srcs: ["lint-baseline.txt"], +} + +filegroup { name: "non-updatable-system-current.txt", srcs: ["system-current.txt"], } diff --git a/core/api/current.txt b/core/api/current.txt index 4c1d51d2e9d8..7cf7e19f865c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12737,7 +12737,7 @@ package android.content.pm { field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access"; field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription"; field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television"; - field public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network"; + field @FlaggedApi("com.android.net.thread.flags.thread_enabled") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network"; field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen"; field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch"; field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct"; @@ -28951,6 +28951,7 @@ package android.net.vcn { method @NonNull public long[] getRetryIntervalsMillis(); method @NonNull public java.util.List<android.net.vcn.VcnUnderlyingNetworkTemplate> getVcnUnderlyingNetworkPriorities(); method public boolean hasGatewayOption(int); + method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled(); field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0 } @@ -28959,6 +28960,7 @@ package android.net.vcn { method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addGatewayOption(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build(); + method @FlaggedApi("android.net.vcn.safe_mode_config") @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder enableSafeMode(boolean); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeGatewayOption(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=0x500) int); @@ -32662,7 +32664,7 @@ package android.os { field public static final int S_V2 = 32; // 0x20 field public static final int TIRAMISU = 33; // 0x21 field public static final int UPSIDE_DOWN_CAKE = 34; // 0x22 - field public static final int VANILLA_ICE_CREAM = 10000; // 0x2710 + field @FlaggedApi("android.os.android_os_build_vanilla_ice_cream") public static final int VANILLA_ICE_CREAM = 10000; // 0x2710 } public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { @@ -33963,7 +33965,7 @@ package android.os { field public static final String DISALLOW_MICROPHONE_TOGGLE = "disallow_microphone_toggle"; field public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"; field public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media"; - field public static final String DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO = "no_near_field_communication_radio"; + field @FlaggedApi("android.nfc.enable_nfc_user_restriction") public static final String DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO = "no_near_field_communication_radio"; field public static final String DISALLOW_NETWORK_RESET = "no_network_reset"; field public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam"; field public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls"; diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt new file mode 100644 index 000000000000..f1c82796d559 --- /dev/null +++ b/core/api/lint-baseline.txt @@ -0,0 +1,7 @@ +// Baseline format: 1.0 +UnflaggedApi: android.content.pm.PackageManager#FEATURE_THREAD_NETWORK: + New API must be flagged with @FlaggedApi: field android.content.pm.PackageManager.FEATURE_THREAD_NETWORK +UnflaggedApi: android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM: + New API must be flagged with @FlaggedApi: field android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM +UnflaggedApi: android.os.UserManager#DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO: + New API must be flagged with @FlaggedApi: field android.os.UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 7cfa1e377933..1a22e9b10ad1 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -14,7 +14,7 @@ package android.app { @UiContext public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback { method public final boolean addDumpable(@NonNull android.util.Dumpable); - method public final boolean isResumed(); + method @FlaggedApi("android.nfc.enable_nfc_mainline") public final boolean isResumed(); } public class ActivityManager { diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt index 27436ce35867..16b8c429ac07 100644 --- a/core/api/module-lib-lint-baseline.txt +++ b/core/api/module-lib-lint-baseline.txt @@ -57,3 +57,11 @@ SamShouldBeLast: android.os.IBinder#linkToDeath(android.os.IBinder.DeathRecipien SAM-compatible parameters (such as parameter 1, "recipient", in android.os.IBinder.linkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.os.IBinder#unlinkToDeath(android.os.IBinder.DeathRecipient, int): SAM-compatible parameters (such as parameter 1, "recipient", in android.os.IBinder.unlinkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions + + +UnflaggedApi: android.app.Activity#isResumed(): + New API must be flagged with @FlaggedApi: method android.app.Activity.isResumed() +UnflaggedApi: android.content.Context#REMOTE_AUTH_SERVICE: + New API must be flagged with @FlaggedApi: field android.content.Context.REMOTE_AUTH_SERVICE +UnflaggedApi: android.os.IpcDataCache#MODULE_TELEPHONY: + New API must be flagged with @FlaggedApi: field android.os.IpcDataCache.MODULE_TELEPHONY diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 64ea1ab0c826..c1b70cb0b526 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3481,7 +3481,7 @@ package android.content { field public static final String SYSTEM_CONFIG_SERVICE = "system_config"; field public static final String SYSTEM_UPDATE_SERVICE = "system_update"; field public static final String TETHERING_SERVICE = "tethering"; - field public static final String THREAD_NETWORK_SERVICE = "thread_network"; + field @FlaggedApi("com.android.net.thread.flags.thread_enabled") public static final String THREAD_NETWORK_SERVICE = "thread_network"; field public static final String TIME_MANAGER_SERVICE = "time_manager"; field public static final String TRANSLATION_MANAGER_SERVICE = "translation"; field public static final String UI_TRANSLATION_SERVICE = "ui_translation"; @@ -10244,6 +10244,7 @@ package android.nfc { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable(); method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean); + method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState(); method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int); method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn(); method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported(); @@ -10254,6 +10255,7 @@ package android.nfc { method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener); + field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC"; field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0 field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe @@ -10315,6 +10317,10 @@ package android.nfc.cardemulation { field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR; } + public final class CardEmulation { + method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int); + } + @FlaggedApi("android.nfc.enable_nfc_mainline") public final class NfcFServiceInfo implements android.os.Parcelable { ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public NfcFServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents(); diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index 71c02dc42c62..1e9e9be881d3 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -226,6 +226,11 @@ SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplora SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams): SAM-compatible parameters (such as parameter 2, "filePathCallback", in android.webkit.WebChromeClient.onShowFileChooser) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions + +UnflaggedApi: android.Manifest.permission#REGISTER_NSD_OFFLOAD_ENGINE: + New API must be flagged with @FlaggedApi: field android.Manifest.permission.REGISTER_NSD_OFFLOAD_ENGINE +UnflaggedApi: android.content.Context#THREAD_NETWORK_SERVICE: + New API must be flagged with @FlaggedApi: field android.content.Context.THREAD_NETWORK_SERVICE UnflaggedApi: android.nfc.cardemulation.AidGroup#CONTENTS_FILE_DESCRIPTOR: New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.AidGroup.CONTENTS_FILE_DESCRIPTOR UnflaggedApi: android.nfc.cardemulation.AidGroup#PARCELABLE_WRITE_RETURN_VALUE: @@ -238,3 +243,7 @@ UnflaggedApi: android.nfc.cardemulation.NfcFServiceInfo#CONTENTS_FILE_DESCRIPTOR New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.NfcFServiceInfo.CONTENTS_FILE_DESCRIPTOR UnflaggedApi: android.nfc.cardemulation.NfcFServiceInfo#PARCELABLE_WRITE_RETURN_VALUE: New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.NfcFServiceInfo.PARCELABLE_WRITE_RETURN_VALUE +UnflaggedApi: android.telephony.mbms.vendor.MbmsDownloadServiceBase#DESCRIPTOR: + New API must be flagged with @FlaggedApi: field android.telephony.mbms.vendor.MbmsDownloadServiceBase.DESCRIPTOR +UnflaggedApi: android.telephony.mbms.vendor.MbmsStreamingServiceBase#DESCRIPTOR: + New API must be flagged with @FlaggedApi: field android.telephony.mbms.vendor.MbmsStreamingServiceBase.DESCRIPTOR diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 726871eccc6c..98f492f1de6d 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -145,6 +145,10 @@ IntentName: android.provider.Telephony.Sms.Intents#SMS_CARRIER_PROVISION_ACTION: Intent action constant name must be ACTION_FOO: SMS_CARRIER_PROVISION_ACTION +KotlinKeyword: android.app.Notification#when: + Avoid field names that are Kotlin hard keywords ("when"); see https://android.github.io/kotlin-guides/interop.html#no-hard-keywords + + KotlinOperator: android.os.PackageTagsList#contains(android.os.PackageTagsList): Method can be invoked as a "in" operator from Kotlin: `contains` (this is usually desirable; just make sure it makes sense for this type of object) KotlinOperator: android.util.SparseArrayMap#get(int, K): @@ -965,16 +969,100 @@ RethrowRemoteException: android.app.ActivityManager#resumeAppSwitches(): Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause) +SamShouldBeLast: android.animation.ValueAnimator#ofObject(android.animation.TypeEvaluator, java.lang.Object...): + SAM-compatible parameters (such as parameter 1, "evaluator", in android.animation.ValueAnimator.ofObject) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.Activity#convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions): + SAM-compatible parameters (such as parameter 1, "callback", in android.app.Activity.convertToTranslucent) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int): + SAM-compatible parameters (such as parameter 1, "listener", in android.app.ActivityManager.addOnUidImportanceListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.AlarmManager#set(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler): + SAM-compatible parameters (such as parameter 4, "listener", in android.app.AlarmManager.set) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.AlarmManager#set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource): + SAM-compatible parameters (such as parameter 5, "listener", in android.app.AlarmManager.set) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.AlarmManager#setExact(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler): + SAM-compatible parameters (such as parameter 4, "listener", in android.app.AlarmManager.setExact) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.AlarmManager#setWindow(int, long, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler): + SAM-compatible parameters (such as parameter 5, "listener", in android.app.AlarmManager.setWindow) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler): + SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, String): + SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, String, android.os.Bundle): + SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.PendingIntent#send(int, android.app.PendingIntent.OnFinished, android.os.Handler): + SAM-compatible parameters (such as parameter 2, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.UiAutomation#executeAndWaitForEvent(Runnable, android.app.UiAutomation.AccessibilityEventFilter, long): + SAM-compatible parameters (such as parameter 2, "filter", in android.app.UiAutomation.executeAndWaitForEvent) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.app.WallpaperManager#addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.app.WallpaperManager.addOnColorsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.ActivityInfo#dump(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ActivityInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.ApplicationInfo#dump(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ApplicationInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.ComponentInfo#dumpBack(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ComponentInfo.dumpBack) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.ComponentInfo#dumpFront(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ComponentInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.PackageItemInfo#dumpBack(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpBack) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.database.sqlite.SQLiteCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]): + SAM-compatible parameters (such as parameter 1, "factory", in android.database.sqlite.SQLiteCursorDriver.query) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]): SAM-compatible parameters (such as parameter 1, "printer", in android.database.sqlite.SQLiteDebug.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]): SAM-compatible parameters (such as parameter 1, "factory", in android.database.sqlite.SQLiteDirectCursorDriver.query) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.graphics.drawable.AdaptiveIconDrawable#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long): + SAM-compatible parameters (such as parameter 2, "what", in android.graphics.drawable.AdaptiveIconDrawable.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.graphics.drawable.Drawable#scheduleSelf(Runnable, long): + SAM-compatible parameters (such as parameter 1, "what", in android.graphics.drawable.Drawable.scheduleSelf) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.graphics.drawable.Drawable.Callback#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long): + SAM-compatible parameters (such as parameter 2, "what", in android.graphics.drawable.Drawable.Callback.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.graphics.drawable.LayerDrawable#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long): + SAM-compatible parameters (such as parameter 2, "what", in android.graphics.drawable.LayerDrawable.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper): + SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper): + SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper): + SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper): + SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper): + SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioManager#abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes): + SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.abandonAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int): + SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy): + SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int): + SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioRecord#addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioRecord.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioRecord#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioRecord.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioTrack.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioTrack.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.media.MediaCas#setEventListener(android.media.MediaCas.EventListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaCas.setEventListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.os.Parcel#createFixedArray(Class<T>, java.util.function.Function<android.os.IBinder,S>, int...): + SAM-compatible parameters (such as parameter 2, "asInterface", in android.os.Parcel.createFixedArray) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String): SAM-compatible parameters (such as parameter 1, "pw", in android.os.StrictMode.ViolationInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.permission.PermissionControllerManager#countPermissionApps(java.util.List<java.lang.String>, int, android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, android.os.Handler): SAM-compatible parameters (such as parameter 3, "callback", in android.permission.PermissionControllerManager.countPermissionApps) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler): SAM-compatible parameters (such as parameter 2, "callback", in android.permission.PermissionControllerManager.getAppPermissions) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, String[], java.security.Principal[], String, int, String): + SAM-compatible parameters (such as parameter 2, "response", in android.security.KeyChain.choosePrivateKeyAlias) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, String[], java.security.Principal[], android.net.Uri, String): + SAM-compatible parameters (such as parameter 2, "response", in android.security.KeyChain.choosePrivateKeyAlias) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int): SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.CharSequenceTransformation.apply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int): @@ -987,8 +1075,24 @@ SamShouldBeLast: android.view.Choreographer#postCallback(int, Runnable, Object): SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.postCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long): SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.postCallbackDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.Choreographer#postFrameCallbackDelayed(android.view.Choreographer.FrameCallback, long): + SAM-compatible parameters (such as parameter 1, "callback", in android.view.Choreographer.postFrameCallbackDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.view.Choreographer#removeCallbacks(int, Runnable, Object): SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.removeCallbacks) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.View#postDelayed(Runnable, long): + SAM-compatible parameters (such as parameter 1, "action", in android.view.View.postDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.View#postOnAnimationDelayed(Runnable, long): + SAM-compatible parameters (such as parameter 1, "action", in android.view.View.postOnAnimationDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.View#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long): + SAM-compatible parameters (such as parameter 2, "what", in android.view.View.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.Window#addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.view.Window.addOnFrameMetricsAvailableListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addAccessibilityStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler): + SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addTouchExplorationStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.view.inputmethod.InputMethodInfo#dump(android.util.Printer, String): + SAM-compatible parameters (such as parameter 1, "pw", in android.view.inputmethod.InputMethodInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions StaticUtils: android.os.health.HealthKeys: @@ -1005,6 +1109,48 @@ StreamFiles: android.os.FileUtils#contains(java.io.File, java.io.File): Methods accepting `File` should also accept `FileDescriptor` or streams: method android.os.FileUtils.contains(java.io.File,java.io.File) +UnflaggedApi: android.app.admin.DevicePolicyIdentifiers#PERMITTED_INPUT_METHODS_POLICY: + New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY +UnflaggedApi: android.app.admin.DevicePolicyIdentifiers#PERSONAL_APPS_SUSPENDED_POLICY: + New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyIdentifiers.PERSONAL_APPS_SUSPENDED_POLICY +UnflaggedApi: android.app.admin.DevicePolicyIdentifiers#SCREEN_CAPTURE_DISABLED_POLICY: + New API must be flagged with @FlaggedApi: field android.app.admin.DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY +UnflaggedApi: android.media.soundtrigger.SoundTriggerInstrumentation#setInPhoneCallState(boolean): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerInstrumentation.setInPhoneCallState(boolean) +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager#createManagerForModule(android.hardware.soundtrigger.SoundTrigger.ModuleProperties): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.createManagerForModule(android.hardware.soundtrigger.SoundTrigger.ModuleProperties) +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager#createManagerForTestModule(): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.createManagerForTestModule() +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager#listModuleProperties(): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.listModuleProperties() +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager#loadSoundModel(android.hardware.soundtrigger.SoundTrigger.SoundModel): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.loadSoundModel(android.hardware.soundtrigger.SoundTrigger.SoundModel) +UnflaggedApi: android.media.soundtrigger.SoundTriggerManager.Model#getSoundModel(): + New API must be flagged with @FlaggedApi: method android.media.soundtrigger.SoundTriggerManager.Model.getSoundModel() +UnflaggedApi: android.os.BatteryManager#BATTERY_PLUGGED_ANY: + New API must be flagged with @FlaggedApi: field android.os.BatteryManager.BATTERY_PLUGGED_ANY +UnflaggedApi: android.os.UserHandle#USER_CURRENT: + New API must be flagged with @FlaggedApi: field android.os.UserHandle.USER_CURRENT +UnflaggedApi: android.os.UserManager#getAliveUsers(): + New API must be flagged with @FlaggedApi: method android.os.UserManager.getAliveUsers() +UnflaggedApi: android.os.UserManager#getUsers(): + New API must be flagged with @FlaggedApi: method android.os.UserManager.getUsers() +UnflaggedApi: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities: + New API must be flagged with @FlaggedApi: class android.telephony.ims.feature.MmTelFeature.MmTelCapabilities +UnflaggedApi: android.view.WindowManager.LayoutParams#preferredMaxDisplayRefreshRate: + New API must be flagged with @FlaggedApi: field android.view.WindowManager.LayoutParams.preferredMaxDisplayRefreshRate +UnflaggedApi: android.view.WindowManager.LayoutParams#preferredMinDisplayRefreshRate: + New API must be flagged with @FlaggedApi: field android.view.WindowManager.LayoutParams.preferredMinDisplayRefreshRate +UnflaggedApi: android.view.inputmethod.InputMethodManager#isCurrentRootView(android.view.View): + New API must be flagged with @FlaggedApi: method android.view.inputmethod.InputMethodManager.isCurrentRootView(android.view.View) +UnflaggedApi: android.view.inputmethod.InsertModeGesture: + New API must be flagged with @FlaggedApi: class android.view.inputmethod.InsertModeGesture +UnflaggedApi: android.window.WindowInfosListenerForTest.WindowInfo#displayId: + New API must be flagged with @FlaggedApi: field android.window.WindowInfosListenerForTest.WindowInfo.displayId +UnflaggedApi: android.window.WindowInfosListenerForTest.WindowInfo#isVisible: + New API must be flagged with @FlaggedApi: field android.window.WindowInfosListenerForTest.WindowInfo.isVisible + + UseIcu: android.hardware.soundtrigger.KeyphraseEnrollmentInfo#getKeyphraseMetadata(String, java.util.Locale) parameter #1: Type `java.util.Locale` should be replaced with richer ICU type `android.icu.util.ULocale` UseIcu: android.hardware.soundtrigger.KeyphraseEnrollmentInfo#getManageKeyphraseIntent(int, String, java.util.Locale) parameter #2: diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 259086932465..06c139f444ef 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -31,6 +31,7 @@ import android.annotation.CallSuper; import android.annotation.CallbackExecutor; import android.annotation.ColorInt; import android.annotation.DrawableRes; +import android.annotation.FlaggedApi; import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.LayoutRes; @@ -79,6 +80,7 @@ import android.graphics.drawable.Icon; import android.media.AudioManager; import android.media.session.MediaController; import android.net.Uri; +import android.nfc.Flags; import android.os.BadParcelableException; import android.os.Build; import android.os.Bundle; @@ -8915,6 +8917,7 @@ public class Activity extends ContextThemeWrapper * @hide */ @UnsupportedAppUsage + @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final boolean isResumed() { return mResumed; diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index e1c45d98e678..164bdbe9f516 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -36,6 +36,7 @@ per-file GameMode* = file:/GAME_MANAGER_OWNERS per-file GameState* = file:/GAME_MANAGER_OWNERS per-file IGameManager* = file:/GAME_MANAGER_OWNERS per-file IGameMode* = file:/GAME_MANAGER_OWNERS +per-file BackgroundStartPrivileges.java = file:/BAL_OWNERS # ActivityThread per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index da5e40aedbd2..f3cc59428a30 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16111,11 +16111,6 @@ public class DevicePolicyManager { * Called by a profile owner of an organization-owned managed profile to suspend personal * apps on the device. When personal apps are suspended the device can only be used for calls. * - * <p>When personal apps are suspended, an ongoing notification about that is shown to the user. - * When the user taps the notification, system invokes {@link #ACTION_CHECK_POLICY_COMPLIANCE} - * in the profile owner package. Profile owner implementation that uses personal apps suspension - * must handle this intent. - * * @param admin Which {@link DeviceAdminReceiver} this request is associated with * @param suspended Whether personal apps should be suspended. * @throws IllegalStateException if the profile owner doesn't have an activity that handles diff --git a/core/java/android/app/contentsuggestions/OWNERS b/core/java/android/app/contentsuggestions/OWNERS index cf54c2a6fcbc..5f8de77c9dda 100644 --- a/core/java/android/app/contentsuggestions/OWNERS +++ b/core/java/android/app/contentsuggestions/OWNERS @@ -1,7 +1,4 @@ # Bug component: 643919 -augale@google.com -joannechung@google.com -markpun@google.com -lpeter@google.com -tymtsai@google.com +hackz@google.com +volnov@google.com diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 10857e51f916..3d43845f1781 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -23,6 +23,7 @@ import android.annotation.ColorInt; import android.annotation.ColorRes; import android.annotation.DisplayContext; import android.annotation.DrawableRes; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.LongDef; import android.annotation.NonNull; @@ -4766,6 +4767,7 @@ public abstract class Context { * @see android.net.thread.ThreadNetworkManager * @hide */ + @FlaggedApi("com.android.net.thread.flags.thread_enabled") @SystemApi public static final String THREAD_NETWORK_SERVICE = "thread_network"; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c3fd744469e9..0fd0e1531771 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1161,6 +1161,11 @@ public class Intent implements Parcelable, Cloneable { * numbers. Applications can <strong>dial</strong> emergency numbers using * {@link #ACTION_DIAL}, however. * + * <p>Note: This Intent can only be used to dial call forwarding MMI codes if the application + * using this intent is set as the default or system dialer. The system will treat any other + * application using this Intent for the purpose of dialing call forwarding MMI codes as if the + * {@link #ACTION_DIAL} Intent was used instead. + * * <p>Note: An app filling the {@link android.app.role.RoleManager#ROLE_DIALER} role should use * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls rather than * relying on this intent. diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 15cdc95c05ea..f07a23f7ba21 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.CheckResult; import android.annotation.DrawableRes; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.LongDef; @@ -3651,6 +3652,7 @@ public abstract class PackageManager { * The device is capable of communicating with other devices via * <a href="https://www.threadgroup.org">Thread</a> networking protocol. */ + @FlaggedApi("com.android.net.thread.flags.thread_enabled") @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network"; diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index 21540bf1a18b..d6c58ac1d7fe 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -1403,6 +1403,7 @@ public final class OutputConfiguration implements Parcelable { if (mSurfaces.get(i) != other.mSurfaces.get(i)) return false; } + if (!mIsDeferredConfig && mSurfaces.size() != other.mSurfaces.size()) return false; if (mDynamicRangeProfile != other.mDynamicRangeProfile) { return false; } diff --git a/core/java/android/hardware/hdmi/OWNERS b/core/java/android/hardware/hdmi/OWNERS index 861e4409b014..6952e5d78d98 100644 --- a/core/java/android/hardware/hdmi/OWNERS +++ b/core/java/android/hardware/hdmi/OWNERS @@ -2,5 +2,4 @@ include /services/core/java/com/android/server/display/OWNERS -marvinramin@google.com -lcnathalie@google.com +quxiangfang@google.com diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index a40fb154c256..779a8db433a8 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,10 +16,12 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; import static com.android.internal.annotations.VisibleForTesting.Visibility; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -235,6 +237,9 @@ public final class VcnGatewayConnectionConfig { "mMinUdpPort4500NatTimeoutSeconds"; private final int mMinUdpPort4500NatTimeoutSeconds; + private static final String IS_SAFE_MODE_DISABLED_KEY = "mIsSafeModeDisabled"; + private final boolean mIsSafeModeDisabled; + private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions"; @NonNull private final Set<Integer> mGatewayOptions; @@ -247,6 +252,7 @@ public final class VcnGatewayConnectionConfig { @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu, @NonNull int minUdpPort4500NatTimeoutSeconds, + boolean isSafeModeDisabled, @NonNull Set<Integer> gatewayOptions) { mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; @@ -255,6 +261,7 @@ public final class VcnGatewayConnectionConfig { mMaxMtu = maxMtu; mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions)); + mIsSafeModeDisabled = isSafeModeDisabled; mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates); if (mUnderlyingNetworkTemplates.isEmpty()) { @@ -317,6 +324,7 @@ public final class VcnGatewayConnectionConfig { in.getInt( MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); + mIsSafeModeDisabled = in.getBoolean(IS_SAFE_MODE_DISABLED_KEY); validate(); } @@ -483,6 +491,16 @@ public final class VcnGatewayConnectionConfig { } /** + * Check whether safe mode is enabled + * + * @see Builder#enableSafeMode(boolean) + */ + @FlaggedApi(FLAG_SAFE_MODE_CONFIG) + public boolean isSafeModeEnabled() { + return !mIsSafeModeDisabled; + } + + /** * Checks if the given VCN gateway option is enabled. * * @param option the option to check. @@ -528,6 +546,7 @@ public final class VcnGatewayConnectionConfig { result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds); + result.putBoolean(IS_SAFE_MODE_DISABLED_KEY, mIsSafeModeDisabled); return result; } @@ -542,6 +561,7 @@ public final class VcnGatewayConnectionConfig { Arrays.hashCode(mRetryIntervalsMs), mMaxMtu, mMinUdpPort4500NatTimeoutSeconds, + mIsSafeModeDisabled, mGatewayOptions); } @@ -559,6 +579,7 @@ public final class VcnGatewayConnectionConfig { && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu && mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds + && mIsSafeModeDisabled == rhs.mIsSafeModeDisabled && mGatewayOptions.equals(rhs.mGatewayOptions); } @@ -577,6 +598,7 @@ public final class VcnGatewayConnectionConfig { @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; + private boolean mIsSafeModeDisabled = false; @NonNull private final Set<Integer> mGatewayOptions = new ArraySet<>(); @@ -789,6 +811,27 @@ public final class VcnGatewayConnectionConfig { } /** + * Enable/disable safe mode + * + * <p>If a VCN fails to provide connectivity within a system-provided timeout, it will enter + * safe mode. In safe mode, the VCN Network will be torn down and the system will restore + * connectivity by allowing underlying cellular networks to be used as default. At the same + * time, VCN will continue to retry until it succeeds. + * + * <p>When safe mode is disabled and VCN connection fails to provide connectivity, end users + * might not have connectivity, and may not have access to carrier-owned underlying + * networks. + * + * @param enabled whether safe mode should be enabled. Defaults to {@code true} + */ + @FlaggedApi(FLAG_SAFE_MODE_CONFIG) + @NonNull + public Builder enableSafeMode(boolean enabled) { + mIsSafeModeDisabled = !enabled; + return this; + } + + /** * Builds and validates the VcnGatewayConnectionConfig. * * @return an immutable VcnGatewayConnectionConfig instance @@ -803,6 +846,7 @@ public final class VcnGatewayConnectionConfig { mRetryIntervalsMs, mMaxMtu, mMinUdpPort4500NatTimeoutSeconds, + mIsSafeModeDisabled, mGatewayOptions); } } diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig new file mode 100644 index 000000000000..6956916af0f1 --- /dev/null +++ b/core/java/android/net/vcn/flags.aconfig @@ -0,0 +1,8 @@ +package: "android.net.vcn" + +flag { + name: "safe_mode_config" + namespace: "vcn" + description: "Feature flag for safe mode configurability" + bug: "276358140" +}
\ No newline at end of file diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl index 53843fe73d33..c7b3b2c03f65 100644 --- a/core/java/android/nfc/INfcCardEmulation.aidl +++ b/core/java/android/nfc/INfcCardEmulation.aidl @@ -40,5 +40,6 @@ interface INfcCardEmulation boolean unsetPreferredService(); boolean supportsAidPrefixRegistration(); ApduServiceInfo getPreferredPaymentService(int userHandle); + boolean setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status); boolean isDefaultPaymentRegistered(); } diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 4a7bd3f29458..c89759553810 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -378,6 +378,8 @@ public final class NfcAdapter { * <p>An external NFC field detected when device locked and SecureNfc enabled. * @hide */ + @SystemApi + @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC"; @@ -944,7 +946,8 @@ public final class NfcAdapter { * * @hide */ - @UnsupportedAppUsage + @SystemApi + @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public int getAdapterState() { try { return sService.getState(); diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java index 958669ee5852..ae3e333051d7 100644 --- a/core/java/android/nfc/cardemulation/AidGroup.java +++ b/core/java/android/nfc/cardemulation/AidGroup.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.regex.Pattern; /********************************************************************** * This file is not a part of the NFC mainline module * @@ -79,7 +80,7 @@ public final class AidGroup implements Parcelable { throw new IllegalArgumentException("Too many AIDs in AID group."); } for (String aid : aids) { - if (!CardEmulation.isValidAid(aid)) { + if (!isValidAid(aid)) { throw new IllegalArgumentException("AID " + aid + " is not a valid AID."); } } @@ -264,4 +265,34 @@ public final class AidGroup implements Parcelable { return CardEmulation.CATEGORY_PAYMENT.equals(category) || CardEmulation.CATEGORY_OTHER.equals(category); } + + private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?"); + /** + * Copied over from {@link CardEmulation#isValidAid(String)} + * @hide + */ + private static boolean isValidAid(String aid) { + if (aid == null) + return false; + + // If a prefix/subset AID, the total length must be odd (even # of AID chars + '*') + if ((aid.endsWith("*") || aid.endsWith("#")) && ((aid.length() % 2) == 0)) { + Log.e(TAG, "AID " + aid + " is not a valid AID."); + return false; + } + + // If not a prefix/subset AID, the total length must be even (even # of AID chars) + if ((!(aid.endsWith("*") || aid.endsWith("#"))) && ((aid.length() % 2) != 0)) { + Log.e(TAG, "AID " + aid + " is not a valid AID."); + return false; + } + + // Verify hex characters + if (!AID_PATTERN.matcher(aid).matches()) { + Log.e(TAG, "AID " + aid + " is not a valid AID."); + return false; + } + + return true; + } } diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java index 18ec914860fb..9cf8c4ddc53b 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -52,6 +52,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; /** * Class holding APDU service info. @@ -126,6 +127,11 @@ public final class ApduServiceInfo implements Parcelable { private final String mSettingsActivityName; /** + * State of the service for CATEGORY_OTHER selection + */ + private boolean mOtherServiceSelectionState; + + /** * @hide */ public ApduServiceInfo(ResolveInfo info, boolean onHost, String description, @@ -133,8 +139,21 @@ public final class ApduServiceInfo implements Parcelable { boolean requiresUnlock, int bannerResource, int uid, String settingsActivityName, String offHost, String staticOffHost) { this(info, onHost, description, staticAidGroups, dynamicAidGroups, + requiresUnlock, bannerResource, uid, settingsActivityName, + offHost, staticOffHost, false); + } + + /** + * @hide + */ + public ApduServiceInfo(ResolveInfo info, boolean onHost, String description, + List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups, + boolean requiresUnlock, int bannerResource, int uid, + String settingsActivityName, String offHost, String staticOffHost, + boolean isSelected) { + this(info, onHost, description, staticAidGroups, dynamicAidGroups, requiresUnlock, onHost ? true : false, bannerResource, uid, - settingsActivityName, offHost, staticOffHost); + settingsActivityName, offHost, staticOffHost, isSelected); } /** @@ -143,7 +162,7 @@ public final class ApduServiceInfo implements Parcelable { public ApduServiceInfo(ResolveInfo info, boolean onHost, String description, List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups, boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid, - String settingsActivityName, String offHost, String staticOffHost) { + String settingsActivityName, String offHost, String staticOffHost, boolean isSelected) { this.mService = info; this.mDescription = description; this.mStaticAidGroups = new HashMap<String, AidGroup>(); @@ -162,6 +181,8 @@ public final class ApduServiceInfo implements Parcelable { this.mBannerResourceId = bannerResource; this.mUid = uid; this.mSettingsActivityName = settingsActivityName; + this.mOtherServiceSelectionState = isSelected; + } /** @@ -307,7 +328,7 @@ public final class ApduServiceInfo implements Parcelable { com.android.internal.R.styleable.AidFilter); String aid = a.getString(com.android.internal.R.styleable.AidFilter_name). toUpperCase(); - if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) { + if (isValidAid(aid) && !currentGroup.getAids().contains(aid)) { currentGroup.getAids().add(aid); } else { Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid); @@ -321,7 +342,7 @@ public final class ApduServiceInfo implements Parcelable { toUpperCase(); // Add wildcard char to indicate prefix aid = aid.concat("*"); - if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) { + if (isValidAid(aid) && !currentGroup.getAids().contains(aid)) { currentGroup.getAids().add(aid); } else { Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid); @@ -335,7 +356,7 @@ public final class ApduServiceInfo implements Parcelable { toUpperCase(); // Add wildcard char to indicate suffix aid = aid.concat("#"); - if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) { + if (isValidAid(aid) && !currentGroup.getAids().contains(aid)) { currentGroup.getAids().add(aid); } else { Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid); @@ -350,6 +371,9 @@ public final class ApduServiceInfo implements Parcelable { } // Set uid mUid = si.applicationInfo.uid; + + mOtherServiceSelectionState = false; // support other category + } /** @@ -719,43 +743,47 @@ public final class ApduServiceInfo implements Parcelable { dest.writeInt(mBannerResourceId); dest.writeInt(mUid); dest.writeString(mSettingsActivityName); + + dest.writeInt(mOtherServiceSelectionState ? 1 : 0); }; @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public static final @NonNull Parcelable.Creator<ApduServiceInfo> CREATOR = new Parcelable.Creator<ApduServiceInfo>() { - @Override - public ApduServiceInfo createFromParcel(Parcel source) { - ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source); - String description = source.readString(); - boolean onHost = source.readInt() != 0; - String offHostName = source.readString(); - String staticOffHostName = source.readString(); - ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>(); - int numStaticGroups = source.readInt(); - if (numStaticGroups > 0) { - source.readTypedList(staticAidGroups, AidGroup.CREATOR); - } - ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>(); - int numDynamicGroups = source.readInt(); - if (numDynamicGroups > 0) { - source.readTypedList(dynamicAidGroups, AidGroup.CREATOR); - } - boolean requiresUnlock = source.readInt() != 0; - boolean requiresScreenOn = source.readInt() != 0; - int bannerResource = source.readInt(); - int uid = source.readInt(); - String settingsActivityName = source.readString(); - return new ApduServiceInfo(info, onHost, description, staticAidGroups, - dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid, - settingsActivityName, offHostName, staticOffHostName); - } + @Override + public ApduServiceInfo createFromParcel(Parcel source) { + ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source); + String description = source.readString(); + boolean onHost = source.readInt() != 0; + String offHostName = source.readString(); + String staticOffHostName = source.readString(); + ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>(); + int numStaticGroups = source.readInt(); + if (numStaticGroups > 0) { + source.readTypedList(staticAidGroups, AidGroup.CREATOR); + } + ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>(); + int numDynamicGroups = source.readInt(); + if (numDynamicGroups > 0) { + source.readTypedList(dynamicAidGroups, AidGroup.CREATOR); + } + boolean requiresUnlock = source.readInt() != 0; + boolean requiresScreenOn = source.readInt() != 0; + int bannerResource = source.readInt(); + int uid = source.readInt(); + String settingsActivityName = source.readString(); + boolean isSelected = source.readInt() != 0; + return new ApduServiceInfo(info, onHost, description, staticAidGroups, + dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid, + settingsActivityName, offHostName, staticOffHostName, + isSelected); + } - @Override - public ApduServiceInfo[] newArray(int size) { - return new ApduServiceInfo[size]; - } - }; + @Override + public ApduServiceInfo[] newArray(int size) { + return new ApduServiceInfo[size]; + } + }; /** * Dump contents for debugging. @@ -778,14 +806,16 @@ public final class ApduServiceInfo implements Parcelable { } pw.println(" Static AID groups:"); for (AidGroup group : mStaticAidGroups.values()) { - pw.println(" Category: " + group.getCategory()); + pw.println(" Category: " + group.getCategory() + + "(selected: " + mOtherServiceSelectionState + ")"); for (String aid : group.getAids()) { pw.println(" AID: " + aid); } } pw.println(" Dynamic AID groups:"); for (AidGroup group : mDynamicAidGroups.values()) { - pw.println(" Category: " + group.getCategory()); + pw.println(" Category: " + group.getCategory() + + "(selected: " + mOtherServiceSelectionState + ")"); for (String aid : group.getAids()) { pw.println(" AID: " + aid); } @@ -795,6 +825,22 @@ public final class ApduServiceInfo implements Parcelable { pw.println(" Requires Device ScreenOn: " + mRequiresDeviceScreenOn); } + + /** + * @hide + */ + public void setOtherServiceState(boolean selected) { + mOtherServiceSelectionState = selected; + } + + + /** + * @hide + */ + public boolean isSelectedOtherService() { + return mOtherServiceSelectionState; + } + /** * Dump debugging info as ApduServiceInfoProto. * @@ -806,7 +852,7 @@ public final class ApduServiceInfo implements Parcelable { */ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void dumpDebug(@NonNull ProtoOutputStream proto) { - Utils.dumpDebugComponentName(getComponent(), proto, ApduServiceInfoProto.COMPONENT_NAME); + getComponent().dumpDebug(proto, ApduServiceInfoProto.COMPONENT_NAME); proto.write(ApduServiceInfoProto.DESCRIPTION, getDescription()); proto.write(ApduServiceInfoProto.ON_HOST, mOnHost); if (!mOnHost) { @@ -825,4 +871,34 @@ public final class ApduServiceInfo implements Parcelable { } proto.write(ApduServiceInfoProto.SETTINGS_ACTIVITY_NAME, mSettingsActivityName); } + + private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?"); + /** + * Copied over from {@link CardEmulation#isValidAid(String)} + * @hide + */ + private static boolean isValidAid(String aid) { + if (aid == null) + return false; + + // If a prefix/subset AID, the total length must be odd (even # of AID chars + '*') + if ((aid.endsWith("*") || aid.endsWith("#")) && ((aid.length() % 2) == 0)) { + Log.e(TAG, "AID " + aid + " is not a valid AID."); + return false; + } + + // If not a prefix/subset AID, the total length must be even (even # of AID chars) + if ((!(aid.endsWith("*") || aid.endsWith("#"))) && ((aid.length() % 2) != 0)) { + Log.e(TAG, "AID " + aid + " is not a valid AID."); + return false; + } + + // Verify hex characters + if (!AID_PATTERN.matcher(aid).matches()) { + Log.e(TAG, "AID " + aid + " is not a valid AID."); + return false; + } + + return true; + } } diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 32c2a1b40530..d048b595ad1e 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -16,17 +16,21 @@ package android.nfc.cardemulation; +import android.annotation.FlaggedApi; 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.UserIdInt; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.nfc.Constants; +import android.nfc.Flags; import android.nfc.INfcCardEmulation; import android.nfc.NfcAdapter; import android.os.RemoteException; @@ -877,9 +881,16 @@ public final class CardEmulation { } /** + * Retrieves list of services registered of the provided category for the provided user. + * + * @param category Category string, one of {@link #CATEGORY_PAYMENT} or {@link #CATEGORY_OTHER} + * @param userId the user handle of the user whose information is being requested. * @hide */ - public List<ApduServiceInfo> getServices(String category, int userId) { + @SystemApi + @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) + @NonNull + public List<ApduServiceInfo> getServices(@NonNull String category, @UserIdInt int userId) { try { return sService.getServices(userId, category); } catch (RemoteException e) { @@ -936,6 +947,39 @@ public final class CardEmulation { return true; } + /** + * Allows to set or unset preferred service (category other) to avoid AID Collision. + * + * @param service The ComponentName of the service + * @param status true to enable, false to disable + * @return set service for the category and true if service is already set return false. + * + * @hide + */ + public boolean setServiceEnabledForCategoryOther(ComponentName service, boolean status) { + if (service == null) { + throw new NullPointerException("activity or service or category is null"); + } + int userId = mContext.getUser().getIdentifier(); + + try { + return sService.setServiceEnabledForCategoryOther(userId, service, status); + } catch (RemoteException e) { + // Try one more time + recoverService(); + if (sService == null) { + Log.e(TAG, "Failed to recover CardEmulationService."); + return false; + } + try { + return sService.setServiceEnabledForCategoryOther(userId, service, status); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to reach CardEmulationService."); + return false; + } + } + } + void recoverService() { NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); sService = adapter.getCardEmulationService(); diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java index ec919e4d66bc..33bc16978721 100644 --- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java +++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java @@ -173,7 +173,7 @@ public final class NfcFServiceInfo implements Parcelable { com.android.internal.R.styleable.SystemCodeFilter); systemCode = a.getString( com.android.internal.R.styleable.SystemCodeFilter_name).toUpperCase(); - if (!NfcFCardEmulation.isValidSystemCode(systemCode) && + if (!isValidSystemCode(systemCode) && !systemCode.equalsIgnoreCase("NULL")) { Log.e(TAG, "Invalid System Code: " + systemCode); systemCode = null; @@ -187,7 +187,7 @@ public final class NfcFServiceInfo implements Parcelable { com.android.internal.R.styleable.Nfcid2Filter_name).toUpperCase(); if (!nfcid2.equalsIgnoreCase("RANDOM") && !nfcid2.equalsIgnoreCase("NULL") && - !NfcFCardEmulation.isValidNfcid2(nfcid2)) { + !isValidNfcid2(nfcid2)) { Log.e(TAG, "Invalid NFCID2: " + nfcid2); nfcid2 = null; } @@ -436,10 +436,62 @@ public final class NfcFServiceInfo implements Parcelable { */ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void dumpDebug(@NonNull ProtoOutputStream proto) { - Utils.dumpDebugComponentName(getComponent(), proto, NfcFServiceInfoProto.COMPONENT_NAME); + getComponent().dumpDebug(proto, NfcFServiceInfoProto.COMPONENT_NAME); proto.write(NfcFServiceInfoProto.DESCRIPTION, getDescription()); proto.write(NfcFServiceInfoProto.SYSTEM_CODE, getSystemCode()); proto.write(NfcFServiceInfoProto.NFCID2, getNfcid2()); proto.write(NfcFServiceInfoProto.T3T_PMM, getT3tPmm()); } + + /** + * Copied over from {@link NfcFCardEmulation#isValidSystemCode(String)} + * @hide + */ + private static boolean isValidSystemCode(String systemCode) { + if (systemCode == null) { + return false; + } + if (systemCode.length() != 4) { + Log.e(TAG, "System Code " + systemCode + " is not a valid System Code."); + return false; + } + // check if the value is between "4000" and "4FFF" (excluding "4*FF") + if (!systemCode.startsWith("4") || systemCode.toUpperCase().endsWith("FF")) { + Log.e(TAG, "System Code " + systemCode + " is not a valid System Code."); + return false; + } + try { + Integer.parseInt(systemCode, 16); + } catch (NumberFormatException e) { + Log.e(TAG, "System Code " + systemCode + " is not a valid System Code."); + return false; + } + return true; + } + + /** + * Copied over from {@link NfcFCardEmulation#isValidNfcid2(String)} + * @hide + */ + private static boolean isValidNfcid2(String nfcid2) { + if (nfcid2 == null) { + return false; + } + if (nfcid2.length() != 16) { + Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2."); + return false; + } + // check if the the value starts with "02FE" + if (!nfcid2.toUpperCase().startsWith("02FE")) { + Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2."); + return false; + } + try { + Long.parseLong(nfcid2, 16); + } catch (NumberFormatException e) { + Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2."); + return false; + } + return true; + } } diff --git a/core/java/android/nfc/flags.aconfig b/core/java/android/nfc/flags.aconfig index 55b0b4261763..cd50ace036de 100644 --- a/core/java/android/nfc/flags.aconfig +++ b/core/java/android/nfc/flags.aconfig @@ -13,3 +13,10 @@ flag { description: "Flag for NFC reader option API changes" bug: "291187960" } + +flag { + name: "enable_nfc_user_restriction" + namespace: "nfc" + description: "Flag for NFC user restriction" + bug: "291187960" +} diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 6a4ec9b7605a..25fba60b9bb5 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -21,6 +21,7 @@ import static android.os.Flags.FLAG_STATE_OF_HEALTH_PUBLIC; import android.Manifest.permission; import android.annotation.FlaggedApi; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -236,6 +237,7 @@ public class BatteryManager { OsProtoEnums.CHARGING_POLICY_ADAPTIVE_LONGLIFE; // = 4 /** @hide */ + @SuppressLint("UnflaggedApi") // TestApi without associated feature. @TestApi public static final int BATTERY_PLUGGED_ANY = BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 509c3b88441e..a9b7257a5406 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -17,6 +17,7 @@ package android.os; import android.Manifest; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -1227,6 +1228,7 @@ public class Build { /** * Vanilla Ice Cream. */ + @FlaggedApi(Flags.FLAG_ANDROID_OS_BUILD_VANILLA_ICE_CREAM) public static final int VANILLA_ICE_CREAM = CUR_DEVELOPMENT; } diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 180735bf48eb..90a40717eada 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -2372,14 +2372,14 @@ public final class StrictMode { } /** Assume locked until we hear otherwise */ - private static volatile boolean sUserKeyUnlocked = false; + private static volatile boolean sCeStorageUnlocked = false; - private static boolean isUserKeyUnlocked(int userId) { + private static boolean isCeStorageUnlocked(int userId) { final IStorageManager storage = IStorageManager.Stub .asInterface(ServiceManager.getService("mount")); if (storage != null) { try { - return storage.isUserKeyUnlocked(userId); + return storage.isCeStorageUnlocked(userId); } catch (RemoteException ignored) { } } @@ -2392,13 +2392,13 @@ public final class StrictMode { // since any relocking of that user will always result in our // process being killed to release any CE FDs we're holding onto. if (userId == UserHandle.myUserId()) { - if (sUserKeyUnlocked) { + if (sCeStorageUnlocked) { return; - } else if (isUserKeyUnlocked(userId)) { - sUserKeyUnlocked = true; + } else if (isCeStorageUnlocked(userId)) { + sCeStorageUnlocked = true; return; } - } else if (isUserKeyUnlocked(userId)) { + } else if (isCeStorageUnlocked(userId)) { return; } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 159394b2b776..bbfd5938774b 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -23,6 +23,7 @@ import android.Manifest; import android.accounts.AccountManager; import android.annotation.ColorInt; import android.annotation.DrawableRes; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -58,6 +59,7 @@ import android.graphics.BitmapFactory; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.location.LocationManager; +import android.nfc.Flags; import android.provider.Settings; import android.util.AndroidException; import android.util.ArraySet; @@ -1831,6 +1833,7 @@ public class UserManager { * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ + @FlaggedApi(Flags.FLAG_ENABLE_NFC_USER_RESTRICTION) public static final String DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO = "no_near_field_communication_radio"; diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 77229c44cc8d..40311535fc1e 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -1,6 +1,13 @@ package: "android.os" flag { + name: "android_os_build_vanilla_ice_cream" + namespace: "build" + description: "Feature flag for adding the VANILLA_ICE_CREAM constant." + bug: "264658905" +} + +flag { name: "state_of_health_public" namespace: "system_sw_battery" description: "Feature flag for making state_of_health a public api." diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index bc52744078ea..25b2aa7842f2 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -134,20 +134,20 @@ interface IStorageManager { @EnforcePermission("MOUNT_UNMOUNT_FILESYSTEMS") void setDebugFlags(int flags, int mask) = 60; @EnforcePermission("STORAGE_INTERNAL") - void createUserKey(int userId, int serialNumber, boolean ephemeral) = 61; + void createUserStorageKeys(int userId, int serialNumber, boolean ephemeral) = 61; @EnforcePermission("STORAGE_INTERNAL") - void destroyUserKey(int userId) = 62; + void destroyUserStorageKeys(int userId) = 62; @EnforcePermission("STORAGE_INTERNAL") - void unlockUserKey(int userId, int serialNumber, in byte[] secret) = 63; + void unlockCeStorage(int userId, int serialNumber, in byte[] secret) = 63; @EnforcePermission("STORAGE_INTERNAL") - void lockUserKey(int userId) = 64; - boolean isUserKeyUnlocked(int userId) = 65; + void lockCeStorage(int userId) = 64; + boolean isCeStorageUnlocked(int userId) = 65; @EnforcePermission("STORAGE_INTERNAL") void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66; @EnforcePermission("STORAGE_INTERNAL") void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67; @EnforcePermission("STORAGE_INTERNAL") - void setUserKeyProtection(int userId, in byte[] secret) = 70; + void setCeStorageProtection(int userId, in byte[] secret) = 70; @EnforcePermission("MOUNT_FORMAT_FILESYSTEMS") void fstrim(int flags, IVoldTaskListener listener) = 72; AppFuseMount mountProxyFileDescriptorBridge() = 73; diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 80dd48825ba7..8e72e13051b0 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -1580,28 +1580,64 @@ public class StorageManager { DEFAULT_FULL_THRESHOLD_BYTES); } - /** {@hide} */ - public void createUserKey(int userId, int serialNumber, boolean ephemeral) { + /** + * Creates the keys for a user's credential-encrypted (CE) and device-encrypted (DE) storage. + * <p> + * This creates the user's CE key and DE key for internal storage, then adds them to the kernel. + * Then, if the user is not ephemeral, this stores the DE key (encrypted) on flash. (The CE key + * is not stored until {@link IStorageManager#setCeStorageProtection()}.) + * <p> + * This does not create the CE and DE directories themselves. For that, see {@link + * #prepareUserStorage()}. + * <p> + * This is only intended to be called by UserManagerService, as part of creating a user. + * + * @param userId ID of the user + * @param serialNumber serial number of the user + * @param ephemeral whether the user is ephemeral + * @throws RuntimeException on error. The user's keys already existing is considered an error. + * @hide + */ + public void createUserStorageKeys(int userId, int serialNumber, boolean ephemeral) { try { - mStorageManager.createUserKey(userId, serialNumber, ephemeral); + mStorageManager.createUserStorageKeys(userId, serialNumber, ephemeral); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - /** {@hide} */ - public void destroyUserKey(int userId) { + /** + * Destroys the keys for a user's credential-encrypted (CE) and device-encrypted (DE) storage. + * <p> + * This evicts the keys from the kernel (if present), which "locks" the corresponding + * directories. Then, this deletes the encrypted keys from flash. This operates on all the + * user's CE and DE keys, for both internal and adoptable storage. + * <p> + * This does not destroy the CE and DE directories themselves. For that, see {@link + * #destroyUserStorage()}. + * <p> + * This is only intended to be called by UserManagerService, as part of removing a user. + * + * @param userId ID of the user + * @throws RuntimeException on error. On error, as many things as possible are still destroyed. + * @hide + */ + public void destroyUserStorageKeys(int userId) { try { - mStorageManager.destroyUserKey(userId); + mStorageManager.destroyUserStorageKeys(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - /** {@hide} */ - public void lockUserKey(int userId) { + /** + * Locks the user's credential-encrypted (CE) storage. + * + * @hide + */ + public void lockCeStorage(int userId) { try { - mStorageManager.lockUserKey(userId); + mStorageManager.lockCeStorage(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1628,17 +1664,26 @@ public class StorageManager { /** {@hide} */ @TestApi public static boolean isUserKeyUnlocked(int userId) { + return isCeStorageUnlocked(userId); + } + + /** + * Returns true if the user's credential-encrypted (CE) storage is unlocked. + * + * @hide + */ + public static boolean isCeStorageUnlocked(int userId) { if (sStorageManager == null) { sStorageManager = IStorageManager.Stub .asInterface(ServiceManager.getService("mount")); } if (sStorageManager == null) { - Slog.w(TAG, "Early during boot, assuming locked"); + Slog.w(TAG, "Early during boot, assuming CE storage is locked"); return false; } final long token = Binder.clearCallingIdentity(); try { - return sStorageManager.isUserKeyUnlocked(userId); + return sStorageManager.isCeStorageUnlocked(userId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } finally { diff --git a/core/java/android/security/OWNERS b/core/java/android/security/OWNERS index 96c0be7f803e..33a67aed6023 100644 --- a/core/java/android/security/OWNERS +++ b/core/java/android/security/OWNERS @@ -8,3 +8,4 @@ per-file *NetworkSecurityPolicy.java = file:net/OWNERS per-file Confirmation*.java = file:/keystore/OWNERS per-file FileIntegrityManager.java = file:platform/system/security:/fsverity/OWNERS per-file IFileIntegrityService.aidl = file:platform/system/security:/fsverity/OWNERS +per-file *.aconfig = victorhsieh@google.com diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index b6c2b83f0daa..5aa309753cc4 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -12,4 +12,5 @@ flag { namespace: "hardware_backed_security" description: "Fix bugs in behavior of UnlockedDeviceRequired keystore keys" bug: "296464083" + is_fixed_read_only: true } diff --git a/core/java/android/window/WindowInfosListenerForTest.java b/core/java/android/window/WindowInfosListenerForTest.java index 25bf85cfaa58..ec792197a329 100644 --- a/core/java/android/window/WindowInfosListenerForTest.java +++ b/core/java/android/window/WindowInfosListenerForTest.java @@ -21,11 +21,13 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.graphics.Rect; +import android.graphics.RectF; import android.os.IBinder; import android.os.InputConfig; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; +import android.util.SparseArray; import android.view.InputWindowHandle; import java.util.ArrayList; @@ -119,13 +121,13 @@ public class WindowInfosListenerForTest { "Exception thrown while waiting for listener to be called with " + "initial state"); } - consumer.accept(buildWindowInfos(windowHandles)); + consumer.accept(buildWindowInfos(windowHandles, displayInfos)); } }; mListeners.put(consumer, listener); Pair<InputWindowHandle[], WindowInfosListener.DisplayInfo[]> initialState = listener.register(); - consumer.accept(buildWindowInfos(initialState.first)); + consumer.accept(buildWindowInfos(initialState.first, initialState.second)); calledWithInitialState.countDown(); } @@ -140,11 +142,28 @@ public class WindowInfosListenerForTest { listener.unregister(); } - private static List<WindowInfo> buildWindowInfos(InputWindowHandle[] windowHandles) { + private static List<WindowInfo> buildWindowInfos( + InputWindowHandle[] windowHandles, WindowInfosListener.DisplayInfo[] displayInfos) { var windowInfos = new ArrayList<WindowInfo>(windowHandles.length); + + var displayInfoById = new SparseArray<WindowInfosListener.DisplayInfo>(displayInfos.length); + for (var displayInfo : displayInfos) { + displayInfoById.put(displayInfo.mDisplayId, displayInfo); + } + + var tmp = new RectF(); for (var handle : windowHandles) { var bounds = new Rect(handle.frameLeft, handle.frameTop, handle.frameRight, handle.frameBottom); + + // Transform bounds from physical display coordinates to logical display coordinates. + var display = displayInfoById.get(handle.displayId); + if (display != null) { + tmp.set(bounds); + display.mTransform.mapRect(tmp); + tmp.round(bounds); + } + windowInfos.add(new WindowInfo(handle.getWindowToken(), handle.name, handle.displayId, bounds, handle.inputConfig)); } diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS new file mode 100644 index 000000000000..fa81ee3905c3 --- /dev/null +++ b/core/java/android/window/flags/OWNERS @@ -0,0 +1 @@ +per-file responsible_apis.aconfig = file:/BAL_OWNERS
\ No newline at end of file diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 965277c4635e..1c5f4f0f1369 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -868,6 +868,11 @@ public final class Zygote { args.mPkgDataInfoList, args.mAllowlistedDataInfoList, args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs); + // While `specializeAppProcess` sets the thread name on the process's main thread, this + // is distinct from the app process name which appears in stack traces, as the latter is + // sourced from the argument buffer of the Process class. Set the app process name here. + Zygote.setAppProcessName(args, TAG); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return ZygoteInit.zygoteInit(args.mTargetSdkVersion, diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 993e4e7b4b3d..5fe086da8c6a 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -296,7 +296,6 @@ class ZygoteConnection { } else { // child; result is a Runnable. zygoteServer.setForkChild(); - Zygote.setAppProcessName(parsedArgs, TAG); // ??? Necessary? return result; } } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index a3e27062fa7b..a3e0016f9174 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1105,10 +1105,9 @@ public class LockPatternUtils { @UnsupportedAppUsage public long setLockoutAttemptDeadline(int userId, int timeoutMs) { final long deadline = SystemClock.elapsedRealtime() + timeoutMs; - if (isSpecialUserId(userId)) { - // For secure password storage (that is required for special users such as FRP), the - // underlying storage also enforces the deadline. Since we cannot store settings - // for special users, don't. + if (userId == USER_FRP) { + // For secure password storage (that is required for FRP), the underlying storage also + // enforces the deadline. Since we cannot store settings for the FRP user, don't. return deadline; } mLockoutDeadlines.put(userId, deadline); @@ -1934,15 +1933,21 @@ public class LockPatternUtils { } /** - * Unlocks the credential-encrypted storage for the given user if the user is not secured, i.e. - * doesn't have an LSKF. + * If the user is not secured, ie doesn't have an LSKF, then decrypt the user's synthetic + * password and use it to unlock various cryptographic keys associated with the user. This + * primarily includes unlocking the user's credential-encrypted (CE) storage. It also includes + * deriving or decrypting the vendor auth secret and sending it to the AuthSecret HAL. + * <p> + * These tasks would normally be done when the LSKF is verified. This method is where these + * tasks are done when the user doesn't have an LSKF. It's called when the user is started. + * <p> + * Except on permission denied, this method doesn't throw an exception on failure. However, the + * last thing that it does is unlock CE storage, and whether CE storage has been successfully + * unlocked can be determined by {@link StorageManager#isCeStorageUnlocked()}. * <p> - * Whether the storage has been unlocked can be determined by - * {@link StorageManager#isUserKeyUnlocked()}. - * * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. * - * @param userId the ID of the user whose storage to unlock + * @param userId the ID of the user whose keys to unlock */ public void unlockUserKeyIfUnsecured(@UserIdInt int userId) { try { diff --git a/core/proto/android/service/OWNERS b/core/proto/android/service/OWNERS index 70cb50f75362..7a19155e4278 100644 --- a/core/proto/android/service/OWNERS +++ b/core/proto/android/service/OWNERS @@ -1 +1,2 @@ per-file sensor_service.proto = arthuri@google.com, bduddie@google.com, stange@google.com +per-file package.proto = file:platform/frameworks/base:/PACKAGE_MANAGER_OWNERS diff --git a/core/tests/GameManagerTests/src/android/app/GameManagerTests.java b/core/tests/GameManagerTests/src/android/app/GameManagerTests.java index fac3a0ecdec2..d34c91ee48ba 100644 --- a/core/tests/GameManagerTests/src/android/app/GameManagerTests.java +++ b/core/tests/GameManagerTests/src/android/app/GameManagerTests.java @@ -86,16 +86,6 @@ public final class GameManagerTests { GameModeInfo gameModeInfo = mGameManager.getGameModeInfo(mPackageName); assertNotNull(gameModeInfo); assertNull(gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_CUSTOM)); - GameModeConfiguration unsupportedFpsConfig = - new GameModeConfiguration.Builder().setFpsOverride( - 70).setScalingFactor(0.5f).build(); - mGameManager.updateCustomGameModeConfiguration(mPackageName, unsupportedFpsConfig); - gameModeInfo = mGameManager.getGameModeInfo(mPackageName); - assertNotNull(gameModeInfo); - // TODO(b/243448953): update to non-zero FPS when matching is implemented - assertEquals(new GameModeConfiguration.Builder().setFpsOverride( - GameModeConfiguration.FPS_OVERRIDE_NONE).setScalingFactor(0.5f).build(), - gameModeInfo.getGameModeConfiguration(GameManager.GAME_MODE_CUSTOM)); GameModeConfiguration supportedFpsConfig = new GameModeConfiguration.Builder().setFpsOverride( diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS index 64f5e6c68a95..5636f9bc436c 100644 --- a/core/tests/coretests/src/android/app/OWNERS +++ b/core/tests/coretests/src/android/app/OWNERS @@ -10,3 +10,7 @@ per-file *UiAutomation* = file:/services/accessibility/OWNERS # KeyguardManagerTest per-file KeyguardManagerTest.java = file:/services/core/java/com/android/server/locksettings/OWNERS + +# Files related to background activity launches +per-file Background*Start* = file:/BAL_OWNERS + diff --git a/core/tests/coretests/src/android/content/BrickDeniedTest.java b/core/tests/coretests/src/android/content/BrickDeniedTest.java deleted file mode 100644 index d8c9baa8df5b..000000000000 --- a/core/tests/coretests/src/android/content/BrickDeniedTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.content; - -import android.test.AndroidTestCase; - -import androidx.test.filters.SmallTest; - -/** Test to make sure brick intents <b>don't</b> work without permission. */ -public class BrickDeniedTest extends AndroidTestCase { - @SmallTest - public void testBrick() { - // Try both the old and new brick intent names. Neither should work, - // since this test application doesn't have the required permission. - // If it does work, well, the test certainly won't pass. - getContext().sendBroadcast(new Intent("SHES_A_BRICK_HOUSE")); - getContext().sendBroadcast(new Intent("android.intent.action.BRICK")); - } -} diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index e27cd978e6be..31092536bac5 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -439,8 +439,10 @@ key usage 0x0c007C KEYBOARD_BACKLIGHT_TOGGLE key usage 0x0c0173 MEDIA_AUDIO_TRACK key usage 0x0c019C PROFILE_SWITCH key usage 0x0c01A2 ALL_APPS -key usage 0x0d0044 STYLUS_BUTTON_PRIMARY -key usage 0x0d005a STYLUS_BUTTON_SECONDARY +# TODO(b/297094448): Add stylus button mappings as a fallback when we have a way to determine +# if a device can actually report it. +# key usage 0x0d0044 STYLUS_BUTTON_PRIMARY +# key usage 0x0d005a STYLUS_BUTTON_SECONDARY # Joystick and game controller axes. # Axes that are not mapped will be assigned generic axis numbers by the input subsystem. diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 1ba41b106f56..b7140355e489 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -1596,6 +1596,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * {@link #getAttestationChallenge()} returns non-null and the spec is used to generate a * symmetric (AES or HMAC) key, {@link javax.crypto.KeyGenerator#generateKey()} will throw * {@link java.security.InvalidAlgorithmParameterException}. + * + * <p>The challenge may be up to 128 bytes. */ @NonNull public Builder setAttestationChallenge(byte[] attestationChallenge) { diff --git a/location/Android.bp b/location/Android.bp index ead46e9b28d9..46dca74e7e40 100644 --- a/location/Android.bp +++ b/location/Android.bp @@ -15,10 +15,27 @@ filegroup { ], } -java_library { - name: "framework-location.stubs.module_lib", +java_sdk_library { + name: "framework-location", srcs: [ ":framework-location-nonupdatable-sources", ], - sdk_version: "core_platform", + defaults: ["framework-non-updatable-unbundled-defaults"], + permitted_packages: [ + "android.location", + "com.android.internal.location", + ], + libs: [ + "app-compat-annotations", + "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage + ], + hidden_api_packages: [ + "com.android.internal.location", + ], + aidl: { + include_dirs: [ + "frameworks/base/location/java", + "frameworks/base/core/java", + ], + }, } diff --git a/location/api/current.txt b/location/api/current.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/location/api/current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/location/api/module-lib-current.txt b/location/api/module-lib-current.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/location/api/module-lib-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/location/api/module-lib-removed.txt b/location/api/module-lib-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/location/api/module-lib-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/location/api/removed.txt b/location/api/removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/location/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/location/api/system-current.txt b/location/api/system-current.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/location/api/system-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/location/api/system-removed.txt b/location/api/system-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/location/api/system-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/location/api/test-current.txt b/location/api/test-current.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/location/api/test-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/location/api/test-removed.txt b/location/api/test-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/location/api/test-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 29e8716f08ac..cda919f14bc6 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -442,6 +442,7 @@ public final class MediaSession { * but it must be released if your activity or service is being destroyed. */ public void release() { + setCallback(null); try { mBinder.destroySession(); } catch (RemoteException e) { diff --git a/media/jni/Android.bp b/media/jni/Android.bp index ed1072cf409f..6031ef70535d 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -81,6 +81,7 @@ cc_library_shared { "libhidlallocatorutils", "libhidlbase", "libsonivox", + "server_configurable_flags", "android.hardware.cas@1.0", "android.hardware.cas.native@1.0", "android.hardware.drm@1.3", @@ -99,6 +100,7 @@ cc_library_shared { static_libs: [ "libgrallocusage", "libmedia_midiiowrapper", + "android.media.playback.flags-aconfig-cc", ], include_dirs: [ diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 14587589372b..2a10fa7957bf 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -35,7 +35,9 @@ #include "android_media_MediaDataSource.h" #include "android_media_Streams.h" #include "android_util_Binder.h" +#include <com_android_media_playback_flags.h> +namespace playback_flags = com::android::media::playback::flags; using namespace android; struct fields_t { @@ -374,9 +376,12 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime( jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } - // For getFrameAtTime family of calls, default to ANDROID_BITMAP_FORMAT_RGB_565 - // to keep the behavior consistent with older releases - AndroidBitmapFormat colorFormat = getColorFormat(env, params, ANDROID_BITMAP_FORMAT_RGB_565); + + AndroidBitmapFormat defaultColorFormat = + playback_flags::mediametadataretriever_default_rgba8888() + ? ANDROID_BITMAP_FORMAT_RGBA_8888 + : ANDROID_BITMAP_FORMAT_RGB_565; + AndroidBitmapFormat colorFormat = getColorFormat(env, params, defaultColorFormat); // Call native method to retrieve a video frame VideoFrame *videoFrame = NULL; diff --git a/media/jni/playback_flags.aconfig b/media/jni/playback_flags.aconfig new file mode 100644 index 000000000000..2bb0ec5375fd --- /dev/null +++ b/media/jni/playback_flags.aconfig @@ -0,0 +1,8 @@ +package: "com.android.media.playback.flags" + +flag { + name: "mediametadataretriever_default_rgba8888" + namespace: "media_solutions" + description: "Change MediaMetadataRetriever to use RGBA8888 for bitmap handling by default." + bug: "298965955" +} diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp index bdd7afeb2f65..7a329bccf940 100644 --- a/media/tests/MediaFrameworkTest/Android.bp +++ b/media/tests/MediaFrameworkTest/Android.bp @@ -20,6 +20,8 @@ android_test { "androidx.test.ext.junit", "androidx.test.rules", "android-ex-camera2", + "android.media.playback.flags-aconfig-java", + "flag-junit", "testables", "testng", "truth", diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java index f70d2d1f8ae7..e3d389737bb0 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java @@ -16,19 +16,27 @@ package com.android.mediaframeworktest.unit; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.graphics.Bitmap; import android.media.MediaMetadataRetriever; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.util.Log; import androidx.test.runner.AndroidJUnit4; +import com.android.media.playback.flags.Flags; import com.android.mediaframeworktest.MediaNames; import com.android.mediaframeworktest.MediaProfileReader; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,6 +48,9 @@ public class MediaMetadataRetrieverTest { private static final String TAG = "MediaMetadataRetrieverTest"; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + // Test album art extraction. @MediumTest @Test @@ -284,6 +295,34 @@ public class MediaMetadataRetrieverTest { assertTrue(!hasFailed); } + /** Test the thumbnail is generated when the default is set to RGBA8888 */ + @MediumTest + // TODO(b/305160754) Remove the following annotation and use SetFlagsRule.enableFlags + @RequiresFlagsEnabled(Flags.FLAG_MEDIAMETADATARETRIEVER_DEFAULT_RGBA8888) + @Test + public void testGetFrameAtTimeWithRGBA8888Flag_Set() throws IOException { + try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) { + retriever.setDataSource(MediaNames.TEST_PATH_1); + Bitmap bitmap = retriever.getFrameAtTime(-1); + assertNotNull(bitmap); + assertEquals(Bitmap.Config.ARGB_8888, bitmap.getConfig()); + } + } + + /** Test the thumbnail is generated when the default is not set to RGBA8888 */ + @MediumTest + // TODO(b/305160754) Remove the following annotation and use SetFlagsRule.disableFlags + @RequiresFlagsDisabled(Flags.FLAG_MEDIAMETADATARETRIEVER_DEFAULT_RGBA8888) + @Test + public void testGetFrameAtTimeWithRGBA8888Flag_Unset() throws IOException { + try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) { + retriever.setDataSource(MediaNames.TEST_PATH_1); + Bitmap bitmap = retriever.getFrameAtTime(-1); + assertNotNull(bitmap); + assertEquals(Bitmap.Config.RGB_565, bitmap.getConfig()); + } + } + // TODO: // Encode and test for the correct mix of metadata elements on a per-file basis? // We should be able to compare the actual returned metadata with the expected metadata diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp index fe3132e3d2a3..ceab164aa324 100644 --- a/native/android/system_fonts.cpp +++ b/native/android/system_fonts.cpp @@ -21,22 +21,20 @@ #include <android/font.h> #include <android/font_matcher.h> #include <android/system_fonts.h> - -#include <memory> -#include <string> -#include <vector> - #include <errno.h> #include <fcntl.h> -#include <libxml/tree.h> -#include <log/log.h> -#include <sys/stat.h> -#include <unistd.h> - #include <hwui/MinikinSkia.h> +#include <libxml/parser.h> +#include <log/log.h> #include <minikin/FontCollection.h> #include <minikin/LocaleList.h> #include <minikin/SystemFonts.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <memory> +#include <string> +#include <vector> struct XmlCharDeleter { void operator()(xmlChar* b) { xmlFree(b); } diff --git a/nfc-extras/OWNERS b/nfc-extras/OWNERS new file mode 100644 index 000000000000..35e9713f5715 --- /dev/null +++ b/nfc-extras/OWNERS @@ -0,0 +1,2 @@ +# Bug component: 48448 +include platform/packages/apps/Nfc:/OWNERS diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java index ffed80479662..fe8386e523b2 100644 --- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java +++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java @@ -16,6 +16,8 @@ package com.android.nfc_extras; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.HashMap; import android.content.Context; @@ -30,6 +32,8 @@ import android.util.Log; * * There is a 1-1 relationship between an {@link NfcAdapterExtras} object and * a {@link NfcAdapter} object. + * + * TODO(b/303286040): Deprecate this API surface since this is no longer supported (see ag/443092) */ public final class NfcAdapterExtras { private static final String TAG = "NfcAdapterExtras"; @@ -72,15 +76,40 @@ public final class NfcAdapterExtras { private final NfcAdapter mAdapter; final String mPackageName; + private static INfcAdapterExtras + getNfcAdapterExtrasInterfaceFromNfcAdapter(NfcAdapter adapter) { + try { + Method method = NfcAdapter.class.getDeclaredMethod("getNfcAdapterExtrasInterface"); + method.setAccessible(true); + return (INfcAdapterExtras) method.invoke(adapter); + } catch (SecurityException | NoSuchMethodException | IllegalArgumentException + | IllegalAccessException | IllegalAccessError | InvocationTargetException e) { + Log.e(TAG, "Unable to get context from NfcAdapter"); + } + return null; + } + /** get service handles */ private static void initService(NfcAdapter adapter) { - final INfcAdapterExtras service = adapter.getNfcAdapterExtrasInterface(); + final INfcAdapterExtras service = getNfcAdapterExtrasInterfaceFromNfcAdapter(adapter); if (service != null) { // Leave stale rather than receive a null value. sService = service; } } + private static Context getContextFromNfcAdapter(NfcAdapter adapter) { + try { + Method method = NfcAdapter.class.getDeclaredMethod("getContext"); + method.setAccessible(true); + return (Context) method.invoke(adapter); + } catch (SecurityException | NoSuchMethodException | IllegalArgumentException + | IllegalAccessException | IllegalAccessError | InvocationTargetException e) { + Log.e(TAG, "Unable to get context from NfcAdapter"); + } + return null; + } + /** * Get the {@link NfcAdapterExtras} for the given {@link NfcAdapter}. * @@ -91,7 +120,7 @@ public final class NfcAdapterExtras { * @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter} */ public static NfcAdapterExtras get(NfcAdapter adapter) { - Context context = adapter.getContext(); + Context context = getContextFromNfcAdapter(adapter); if (context == null) { throw new UnsupportedOperationException( "You must pass a context to your NfcAdapter to use the NFC extras APIs"); @@ -112,7 +141,7 @@ public final class NfcAdapterExtras { private NfcAdapterExtras(NfcAdapter adapter) { mAdapter = adapter; - mPackageName = adapter.getContext().getPackageName(); + mPackageName = getContextFromNfcAdapter(adapter).getPackageName(); mEmbeddedEe = new NfcExecutionEnvironment(this); mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, mEmbeddedEe); @@ -156,12 +185,24 @@ public final class NfcAdapterExtras { } } + private static void attemptDeadServiceRecoveryOnNfcAdapter(NfcAdapter adapter, Exception e) { + try { + Method method = NfcAdapter.class.getDeclaredMethod( + "attemptDeadServiceRecovery", Exception.class); + method.setAccessible(true); + method.invoke(adapter, e); + } catch (SecurityException | NoSuchMethodException | IllegalArgumentException + | IllegalAccessException | IllegalAccessError | InvocationTargetException ex) { + Log.e(TAG, "Unable to attempt dead service recovery on NfcAdapter"); + } + } + /** * NFC service dead - attempt best effort recovery */ void attemptDeadServiceRecovery(Exception e) { Log.e(TAG, "NFC Adapter Extras dead - attempting to recover"); - mAdapter.attemptDeadServiceRecovery(e); + attemptDeadServiceRecoveryOnNfcAdapter(mAdapter, e); initService(mAdapter); } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java index 3505cfb9d38a..74f04e093162 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java @@ -33,8 +33,6 @@ import android.view.View; import androidx.annotation.Nullable; -import java.io.File; - /** * Installation failed: Return status code to the caller or display failure UI to user */ @@ -101,14 +99,8 @@ public class InstallFailed extends AlertActivity { // Set header icon and title PackageUtil.AppSnippet as; PackageManager pm = getPackageManager(); - - if ("package".equals(packageURI.getScheme())) { - as = new PackageUtil.AppSnippet(pm.getApplicationLabel(appInfo), - pm.getApplicationIcon(appInfo)); - } else { - final File sourceFile = new File(packageURI.getPath()); - as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); - } + as = intent.getParcelableExtra(PackageInstallerActivity.EXTRA_APP_SNIPPET, + PackageUtil.AppSnippet.class); // Store label for dialog mLabel = as.label; diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java index 7bea33971259..1088acef0fb0 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java @@ -16,6 +16,7 @@ package com.android.packageinstaller; +import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_APP_SNIPPET; import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID; import android.app.PendingIntent; @@ -86,7 +87,8 @@ public class InstallInstalling extends AlertActivity { // ContentResolver.SCHEME_FILE // STAGED_SESSION_ID extra contains an ID of a previously staged install session. final File sourceFile = new File(mPackageURI.getPath()); - PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); + PackageUtil.AppSnippet as = getIntent() + .getParcelableExtra(EXTRA_APP_SNIPPET, PackageUtil.AppSnippet.class); mAlert.setIcon(as.icon); mAlert.setTitle(as.label); diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java index 73c03a57cade..579fb7b7de06 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; @@ -31,7 +30,6 @@ import android.widget.Button; import androidx.annotation.Nullable; -import java.io.File; import java.util.List; /** @@ -66,18 +64,8 @@ public class InstallSuccess extends AlertActivity { ApplicationInfo appInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mAppPackageName = appInfo.packageName; - Uri packageURI = intent.getData(); - - // Set header icon and title - PackageManager pm = getPackageManager(); - - if ("package".equals(packageURI.getScheme())) { - mAppSnippet = new PackageUtil.AppSnippet(pm.getApplicationLabel(appInfo), - pm.getApplicationIcon(appInfo)); - } else { - File sourceFile = new File(packageURI.getPath()); - mAppSnippet = PackageUtil.getAppSnippet(this, appInfo, sourceFile); - } + mAppSnippet = intent.getParcelableExtra(PackageInstallerActivity.EXTRA_APP_SNIPPET, + PackageUtil.AppSnippet.class); mLaunchIntent = getPackageManager().getLaunchIntentForPackage(mAppPackageName); diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index 38d5d3a15914..1e201689ed6a 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -81,6 +81,7 @@ public class PackageInstallerActivity extends AlertActivity { static final String EXTRA_CALLING_ATTRIBUTION_TAG = "EXTRA_CALLING_ATTRIBUTION_TAG"; static final String EXTRA_ORIGINAL_SOURCE_INFO = "EXTRA_ORIGINAL_SOURCE_INFO"; static final String EXTRA_STAGED_SESSION_ID = "EXTRA_STAGED_SESSION_ID"; + static final String EXTRA_APP_SNIPPET = "EXTRA_APP_SNIPPET"; private static final String ALLOW_UNKNOWN_SOURCES_KEY = PackageInstallerActivity.class.getName() + "ALLOW_UNKNOWN_SOURCES_KEY"; @@ -595,7 +596,7 @@ public class PackageInstallerActivity extends AlertActivity { CharSequence label = mPm.getApplicationLabel(mPkgInfo.applicationInfo); if (mLocalLOGV) Log.i(TAG, "creating snippet for " + label); mAppSnippet = new PackageUtil.AppSnippet(label, - mPm.getApplicationIcon(mPkgInfo.applicationInfo)); + mPm.getApplicationIcon(mPkgInfo.applicationInfo), getBaseContext()); } break; case ContentResolver.SCHEME_FILE: { @@ -633,7 +634,7 @@ public class PackageInstallerActivity extends AlertActivity { mPkgInfo = generateStubPackageInfo(info.getAppPackageName()); mAppSnippet = new PackageUtil.AppSnippet(info.getAppLabel(), info.getAppIcon() != null ? new BitmapDrawable(getResources(), info.getAppIcon()) - : getPackageManager().getDefaultActivityIcon()); + : getPackageManager().getDefaultActivityIcon(), getBaseContext()); return true; } @@ -693,6 +694,9 @@ public class PackageInstallerActivity extends AlertActivity { if (stagedSessionId > 0) { newIntent.putExtra(EXTRA_STAGED_SESSION_ID, stagedSessionId); } + if (mAppSnippet != null) { + newIntent.putExtra(EXTRA_APP_SNIPPET, mAppSnippet); + } newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); if (mLocalLOGV) Log.i(TAG, "downloaded app uri=" + mPackageURI); startActivity(newIntent); diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java index ff0e5fb296b1..f6f7acc0e77c 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java @@ -18,6 +18,7 @@ package com.android.packageinstaller; import android.app.Activity; +import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; @@ -27,8 +28,13 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; import android.os.UserHandle; import android.util.Log; import android.view.View; @@ -115,18 +121,75 @@ public class PackageUtil { icon); } - static final class AppSnippet { + static final class AppSnippet implements Parcelable { @NonNull public CharSequence label; @Nullable public Drawable icon; - public AppSnippet(@NonNull CharSequence label, @Nullable Drawable icon) { + public int iconSize; + + public AppSnippet(@NonNull CharSequence label, @Nullable Drawable icon, Context context) { this.label = label; this.icon = icon; + final ActivityManager am = context.getSystemService(ActivityManager.class); + this.iconSize = am.getLauncherLargeIconSize(); + } + + private AppSnippet(Parcel in) { + label = in.readString(); + Bitmap bmp = in.readParcelable(getClass().getClassLoader(), Bitmap.class); + icon = new BitmapDrawable(Resources.getSystem(), bmp); + iconSize = in.readInt(); } @Override public String toString() { return "AppSnippet[" + label + (icon != null ? "(has" : "(no ") + " icon)]"; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(label.toString()); + Bitmap bmp = getBitmapFromDrawable(icon); + dest.writeParcelable(bmp, 0); + dest.writeInt(iconSize); + } + + private Bitmap getBitmapFromDrawable(Drawable drawable) { + // Create an empty bitmap with the dimensions of our drawable + final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), + Bitmap.Config.ARGB_8888); + // Associate it with a canvas. This canvas will draw the icon on the bitmap + final Canvas canvas = new Canvas(bmp); + // Draw the drawable in the canvas. The canvas will ultimately paint the drawable in the + // bitmap held within + drawable.draw(canvas); + + // Scale it down if the icon is too large + if ((bmp.getWidth() > iconSize * 2) || (bmp.getHeight() > iconSize * 2)) { + Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp, iconSize, iconSize, true); + if (scaledBitmap != bmp) { + bmp.recycle(); + } + return scaledBitmap; + } + + return bmp; + } + + public static final Parcelable.Creator<AppSnippet> CREATOR = new Parcelable.Creator<>() { + public AppSnippet createFromParcel(Parcel in) { + return new AppSnippet(in); + } + + public AppSnippet[] newArray(int size) { + return new AppSnippet[size]; + } + }; } /** @@ -171,7 +234,7 @@ public class PackageUtil { } catch (OutOfMemoryError e) { Log.i(LOG_TAG, "Could not load app icon", e); } - return new PackageUtil.AppSnippet(label, icon); + return new PackageUtil.AppSnippet(label, icon, pContext); } /** diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index 8f329b3dddd8..34545cf190f3 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -36,6 +36,7 @@ gwasserman@google.com hwwang@google.com hyunyoungs@google.com ikateryna@google.com +iyz@google.com jaggies@google.com jamesoleary@google.com jbolinger@google.com @@ -54,10 +55,12 @@ justinweir@google.com kozynski@google.com kprevas@google.com lusilva@google.com +liuyining@google.com lynhan@google.com madym@google.com mankoff@google.com mateuszc@google.com +matiashe@google.com mgalhardo@google.com michaelmikhil@google.com michschn@google.com @@ -94,6 +97,7 @@ tracyzhou@google.com tsuji@google.com twickham@google.com vadimt@google.com +valiiftime@google.com vanjan@google.com victortulias@google.com winsonc@google.com diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/OWNERS new file mode 100644 index 000000000000..7f5384d1dbf3 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/OWNERS @@ -0,0 +1,3 @@ +set noparent + +include /packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
\ No newline at end of file diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java index 1866a9983495..67c2caa338a6 100644 --- a/rs/java/android/renderscript/ScriptC.java +++ b/rs/java/android/renderscript/ScriptC.java @@ -16,9 +16,12 @@ package android.renderscript; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.content.res.Resources; +import android.util.Slog; -import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -35,6 +38,15 @@ public class ScriptC extends Script { private static final String TAG = "ScriptC"; /** + * In targetSdkVersion 35 and above, Renderscript's ScriptC stops being supported + * and an exception is thrown when the class is instantiated. + * In targetSdkVersion 34 and below, Renderscript's ScriptC still works. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = 35) + private static final long RENDERSCRIPT_SCRIPTC_DEPRECATION_CHANGE_ID = 297019750L; + + /** * Only intended for use by the generated derived classes. * * @param id @@ -89,7 +101,19 @@ public class ScriptC extends Script { setID(id); } + private static void throwExceptionIfSDKTooHigh() { + String message = + "ScriptC scripts are not supported when targeting an API Level >= 35. Please refer " + + "to https://developer.android.com/guide/topics/renderscript/migration-guide " + + "for proposed alternatives."; + Slog.w(TAG, message); + if (CompatChanges.isChangeEnabled(RENDERSCRIPT_SCRIPTC_DEPRECATION_CHANGE_ID)) { + throw new UnsupportedOperationException(message); + } + } + private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) { + throwExceptionIfSDKTooHigh(); byte[] pgm; int pgmLength; InputStream is = resources.openRawResource(resourceID); @@ -126,6 +150,7 @@ public class ScriptC extends Script { private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) { // Log.v(TAG, "Create script for resource = " + resName); + throwExceptionIfSDKTooHigh(); return rs.nScriptCCreate(resName, RenderScript.getCachePath(), bitcode, bitcode.length); } } diff --git a/services/Android.bp b/services/Android.bp index 66181f5ed45c..3a0428e0a9f8 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -235,12 +235,14 @@ filegroup { stubs_defaults { name: "services-stubs-default", installable: false, - args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\)" + - " --hide-annotation android.annotation.Hide" + - " --hide InternalClasses" + // com.android.* classes are okay in this interface + flags: [ + "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\)", + "--hide-annotation android.annotation.Hide", + "--hide InternalClasses", // com.android.* classes are okay in this interface // TODO: remove the --hide options below - " --hide DeprecationMismatch" + - " --hide HiddenTypedefConstant", + "--hide DeprecationMismatch", + "--hide HiddenTypedefConstant", + ], visibility: ["//frameworks/base:__subpackages__"], filter_packages: ["com.android."], } diff --git a/services/core/Android.bp b/services/core/Android.bp index 189ab19763ac..22f85703f428 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -118,7 +118,6 @@ java_library_static { ":display-device-config", ":display-layout-config", ":device-state-config", - ":framework-core-nfc-infcadapter-sources", "java/com/android/server/EventLogTags.logtags", "java/com/android/server/am/EventLogTags.logtags", "java/com/android/server/wm/EventLogTags.logtags", @@ -131,6 +130,7 @@ java_library_static { "android.hardware.light-V2.0-java", "android.hardware.gnss-V2-java", "android.hardware.vibrator-V2-java", + "android.nfc.flags-aconfig-java", "app-compat-annotations", "framework-tethering.stubs.module_lib", "service-art.stubs.system_server", @@ -179,7 +179,6 @@ java_library_static { "android.hardware.power.stats-V2-java", "android.hardware.power-V4-java", "android.hidl.manager-V1.2-java", - "android.nfc.flags-aconfig-java", "cbor-java", "icu4j_calendar_astronomer", "android.security.aaid_aidl-java", diff --git a/services/core/java/com/android/server/BrickReceiver.java b/services/core/java/com/android/server/BrickReceiver.java deleted file mode 100644 index cff3805b68d2..000000000000 --- a/services/core/java/com/android/server/BrickReceiver.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.content.Context; -import android.content.Intent; -import android.content.BroadcastReceiver; -import android.os.SystemService; -import android.util.Slog; - -public class BrickReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - Slog.w("BrickReceiver", "!!! BRICKING DEVICE !!!"); - SystemService.start("brick"); - } -} diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 71428284882d..61584b727aa7 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -377,15 +377,14 @@ class StorageManagerService extends IStorageManager.Stub private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_STORAGE); /** - * mLocalUnlockedUsers affects the return value of isUserUnlocked. If - * any value in the array changes, then the binder cache for - * isUserUnlocked must be invalidated. When adding mutating methods to - * WatchedLockedUsers, be sure to invalidate the cache in the new - * methods. + * mCeUnlockedUsers affects the return value of {@link UserManager#isUserUnlocked}. If any + * value in the array changes, then the binder cache for {@link UserManager#isUserUnlocked} must + * be invalidated. When adding mutating methods to this class, be sure to invalidate the cache + * in the new methods. */ - private static class WatchedLockedUsers { + private static class WatchedUnlockedUsers { private int[] users = EmptyArray.INT; - public WatchedLockedUsers() { + public WatchedUnlockedUsers() { invalidateIsUserUnlockedCache(); } public void append(int userId) { @@ -417,10 +416,14 @@ class StorageManagerService extends IStorageManager.Stub } } - /** Set of users that we know are unlocked. */ + /** Set of users whose CE storage is unlocked. */ @GuardedBy("mLock") - private WatchedLockedUsers mLocalUnlockedUsers = new WatchedLockedUsers(); - /** Set of users that system knows are unlocked. */ + private WatchedUnlockedUsers mCeUnlockedUsers = new WatchedUnlockedUsers(); + + /** + * Set of users that are in the RUNNING_UNLOCKED state. This differs from {@link + * mCeUnlockedUsers} in that a user can be stopped but still have its CE storage unlocked. + */ @GuardedBy("mLock") private int[] mSystemUnlockedUsers = EmptyArray.INT; @@ -1135,11 +1138,10 @@ class StorageManagerService extends IStorageManager.Stub } } - // If vold knows that some users have their storage unlocked already (which - // can happen after a "userspace reboot"), then add those users to - // mLocalUnlockedUsers. Do this right away and don't wait until - // PHASE_BOOT_COMPLETED, since the system may unlock users before then. - private void restoreLocalUnlockedUsers() { + // If vold knows that some users have their CE storage unlocked already (which can happen after + // a "userspace reboot"), then add those users to mCeUnlockedUsers. Do this right away and + // don't wait until PHASE_BOOT_COMPLETED, since the system may unlock users before then. + private void restoreCeUnlockedUsers() { final int[] userIds; try { userIds = mVold.getUnlockedUsers(); @@ -1155,7 +1157,7 @@ class StorageManagerService extends IStorageManager.Stub // reconnecting to vold after it crashed and was restarted, in // which case things will be the other way around --- we'll know // about the unlocked users but vold won't. - mLocalUnlockedUsers.appendAll(userIds); + mCeUnlockedUsers.appendAll(userIds); } } } @@ -2062,7 +2064,7 @@ class StorageManagerService extends IStorageManager.Stub connectVold(); }, DateUtils.SECOND_IN_MILLIS); } else { - restoreLocalUnlockedUsers(); + restoreCeUnlockedUsers(); onDaemonConnected(); } } @@ -2982,7 +2984,7 @@ class StorageManagerService extends IStorageManager.Stub // We need all the users unlocked to move their primary storage users = mContext.getSystemService(UserManager.class).getUsers(); for (UserInfo user : users) { - if (StorageManager.isFileEncrypted() && !isUserKeyUnlocked(user.id)) { + if (StorageManager.isFileEncrypted() && !isCeStorageUnlocked(user.id)) { Slog.w(TAG, "Failing move due to locked user " + user.id); onMoveStatusLocked(PackageManager.MOVE_FAILED_LOCKED_USER); return; @@ -3206,15 +3208,15 @@ class StorageManagerService extends IStorageManager.Stub @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL) @Override - public void createUserKey(int userId, int serialNumber, boolean ephemeral) { + public void createUserStorageKeys(int userId, int serialNumber, boolean ephemeral) { - super.createUserKey_enforcePermission(); + super.createUserStorageKeys_enforcePermission(); try { - mVold.createUserKey(userId, serialNumber, ephemeral); - // New keys are always unlocked. + mVold.createUserStorageKeys(userId, serialNumber, ephemeral); + // Since the user's CE key was just created, the user's CE storage is now unlocked. synchronized (mLock) { - mLocalUnlockedUsers.append(userId); + mCeUnlockedUsers.append(userId); } } catch (Exception e) { Slog.wtf(TAG, e); @@ -3223,15 +3225,15 @@ class StorageManagerService extends IStorageManager.Stub @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL) @Override - public void destroyUserKey(int userId) { + public void destroyUserStorageKeys(int userId) { - super.destroyUserKey_enforcePermission(); + super.destroyUserStorageKeys_enforcePermission(); try { - mVold.destroyUserKey(userId); - // Destroying a key also locks it. + mVold.destroyUserStorageKeys(userId); + // Since the user's CE key was just destroyed, the user's CE storage is now locked. synchronized (mLock) { - mLocalUnlockedUsers.remove(userId); + mCeUnlockedUsers.remove(userId); } } catch (Exception e) { Slog.wtf(TAG, e); @@ -3241,60 +3243,60 @@ class StorageManagerService extends IStorageManager.Stub /* Only for use by LockSettingsService */ @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL) @Override - public void setUserKeyProtection(@UserIdInt int userId, byte[] secret) throws RemoteException { - super.setUserKeyProtection_enforcePermission(); + public void setCeStorageProtection(@UserIdInt int userId, byte[] secret) + throws RemoteException { + super.setCeStorageProtection_enforcePermission(); - mVold.setUserKeyProtection(userId, HexDump.toHexString(secret)); + mVold.setCeStorageProtection(userId, HexDump.toHexString(secret)); } /* Only for use by LockSettingsService */ @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL) @Override - public void unlockUserKey(@UserIdInt int userId, int serialNumber, byte[] secret) - throws RemoteException { - super.unlockUserKey_enforcePermission(); + public void unlockCeStorage(@UserIdInt int userId, int serialNumber, byte[] secret) + throws RemoteException { + super.unlockCeStorage_enforcePermission(); if (StorageManager.isFileEncrypted()) { - mVold.unlockUserKey(userId, serialNumber, HexDump.toHexString(secret)); + mVold.unlockCeStorage(userId, serialNumber, HexDump.toHexString(secret)); } synchronized (mLock) { - mLocalUnlockedUsers.append(userId); + mCeUnlockedUsers.append(userId); } } @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL) @Override - public void lockUserKey(int userId) { - // Do not lock user 0 data for headless system user - super.lockUserKey_enforcePermission(); + public void lockCeStorage(int userId) { + super.lockCeStorage_enforcePermission(); + // Never lock the CE storage of a headless system user. if (userId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) { throw new IllegalArgumentException("Headless system user data cannot be locked.."); } - - if (!isUserKeyUnlocked(userId)) { + if (!isCeStorageUnlocked(userId)) { Slog.d(TAG, "User " + userId + "'s CE storage is already locked"); return; } try { - mVold.lockUserKey(userId); + mVold.lockCeStorage(userId); } catch (Exception e) { Slog.wtf(TAG, e); return; } synchronized (mLock) { - mLocalUnlockedUsers.remove(userId); + mCeUnlockedUsers.remove(userId); } } @Override - public boolean isUserKeyUnlocked(int userId) { + public boolean isCeStorageUnlocked(int userId) { synchronized (mLock) { - return mLocalUnlockedUsers.contains(userId); + return mCeUnlockedUsers.contains(userId); } } @@ -3679,8 +3681,8 @@ class StorageManagerService extends IStorageManager.Stub final int userId = UserHandle.getUserId(callingUid); final String propertyName = "sys.user." + userId + ".ce_available"; - // Ignore requests to create directories while storage is locked - if (!isUserKeyUnlocked(userId)) { + // Ignore requests to create directories while CE storage is locked + if (!isCeStorageUnlocked(userId)) { throw new IllegalStateException("Failed to prepare " + appPath); } @@ -3806,15 +3808,15 @@ class StorageManagerService extends IStorageManager.Stub final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM); final boolean userIsDemo; - final boolean userKeyUnlocked; final boolean storagePermission; + final boolean ceStorageUnlocked; final long token = Binder.clearCallingIdentity(); try { userIsDemo = LocalServices.getService(UserManagerInternal.class) .getUserInfo(userId).isDemo(); storagePermission = mStorageManagerInternal.hasExternalStorage(callingUid, callingPackage); - userKeyUnlocked = isUserKeyUnlocked(userId); + ceStorageUnlocked = isCeStorageUnlocked(userId); } finally { Binder.restoreCallingIdentity(token); } @@ -3874,7 +3876,7 @@ class StorageManagerService extends IStorageManager.Stub } else if (!systemUserUnlocked) { reportUnmounted = true; Slog.w(TAG, "Reporting " + volId + " unmounted due to system locked"); - } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) { + } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !ceStorageUnlocked) { reportUnmounted = true; Slog.w(TAG, "Reporting " + volId + "unmounted due to " + userId + " locked"); } else if (!storagePermission && !realState) { @@ -4678,7 +4680,7 @@ class StorageManagerService extends IStorageManager.Stub } pw.println(); - pw.println("Local unlocked users: " + mLocalUnlockedUsers); + pw.println("CE unlocked users: " + mCeUnlockedUsers); pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers)); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e6df1d91861a..e74371e6a66b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2249,7 +2249,7 @@ public class ActivityManagerService extends IActivityManager.Stub return; } // TODO(b/148767783): should we check all profiles under user0? - UserspaceRebootLogger.logEventAsync(StorageManager.isUserKeyUnlocked(userId), + UserspaceRebootLogger.logEventAsync(StorageManager.isCeStorageUnlocked(userId), BackgroundThread.getExecutor()); } @@ -4564,7 +4564,7 @@ public class ActivityManagerService extends IActivityManager.Stub // We carefully use the same state that PackageManager uses for // filtering, since we use this flag to decide if we need to install // providers when user is unlocked later - app.setUnlocked(StorageManager.isUserKeyUnlocked(app.userId)); + app.setUnlocked(StorageManager.isCeStorageUnlocked(app.userId)); } boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 2e45da3c8d42..d56448d43e43 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1174,7 +1174,7 @@ final class ActivityManagerShellCommand extends ShellCommand { synchronized (mInternal.mOomAdjuster.mCachedAppOptimizer.mFreezerLock) { app.mOptRecord.setFreezeSticky(isSticky); mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppInternalLSP(app, 0, - false); + true); } } } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 76a994ec63e9..6eb2961fcf86 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -639,8 +639,8 @@ class UserController implements Handler.Callback { mInjector.getUserJourneyLogger() .logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_UNLOCKING_USER, EVENT_STATE_BEGIN); - // If the user key hasn't been unlocked yet, we cannot proceed. - if (!StorageManager.isUserKeyUnlocked(userId)) return false; + // If the user's CE storage hasn't been unlocked yet, we cannot proceed. + if (!StorageManager.isCeStorageUnlocked(userId)) return false; synchronized (mLock) { // Do not proceed if unexpected state or a stale user if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) { @@ -655,8 +655,8 @@ class UserController implements Handler.Callback { // Call onBeforeUnlockUser on a worker thread that allows disk I/O FgThread.getHandler().post(() -> { - if (!StorageManager.isUserKeyUnlocked(userId)) { - Slogf.w(TAG, "User key got locked unexpectedly, leaving user locked."); + if (!StorageManager.isCeStorageUnlocked(userId)) { + Slogf.w(TAG, "User's CE storage got locked unexpectedly, leaving user locked."); return; } @@ -690,8 +690,8 @@ class UserController implements Handler.Callback { private void finishUserUnlocked(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); EventLog.writeEvent(EventLogTags.UC_FINISH_USER_UNLOCKED, userId); - // Only keep marching forward if user is actually unlocked - if (!StorageManager.isUserKeyUnlocked(userId)) return; + // Only keep marching forward if the user's CE storage is unlocked. + if (!StorageManager.isCeStorageUnlocked(userId)) return; synchronized (mLock) { // Bail if we ended up with a stale user if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; @@ -777,8 +777,8 @@ class UserController implements Handler.Callback { if (userInfo == null) { return; } - // Only keep marching forward if user is actually unlocked - if (!StorageManager.isUserKeyUnlocked(userId)) return; + // Only keep marching forward if the user's CE storage is unlocked. + if (!StorageManager.isCeStorageUnlocked(userId)) return; // Remember that we logged in mInjector.getUserManager().onUserLoggedIn(userId); @@ -1256,7 +1256,7 @@ class UserController implements Handler.Callback { } try { Slogf.i(TAG, "Locking CE storage for user #" + userId); - mInjector.getStorageManager().lockUserKey(userId); + mInjector.getStorageManager().lockCeStorage(userId); } catch (RemoteException re) { throw re.rethrowAsRuntimeException(); } @@ -1874,8 +1874,8 @@ class UserController implements Handler.Callback { } UserState uss; - if (!StorageManager.isUserKeyUnlocked(userId)) { - // We always want to try to unlock the user key, even if the user is not started yet. + if (!StorageManager.isCeStorageUnlocked(userId)) { + // We always want to try to unlock CE storage, even if the user is not started yet. mLockPatternUtils.unlockUserKeyIfUnsecured(userId); } synchronized (mLock) { @@ -2662,10 +2662,10 @@ class UserController implements Handler.Callback { case UserState.STATE_RUNNING_UNLOCKING: case UserState.STATE_RUNNING_UNLOCKED: return true; - // In the stopping/shutdown state return unlock state of the user key + // In the stopping/shutdown state, return unlock state of the user's CE storage. case UserState.STATE_STOPPING: case UserState.STATE_SHUTDOWN: - return StorageManager.isUserKeyUnlocked(userId); + return StorageManager.isCeStorageUnlocked(userId); default: return false; } @@ -2674,10 +2674,10 @@ class UserController implements Handler.Callback { switch (state.state) { case UserState.STATE_RUNNING_UNLOCKED: return true; - // In the stopping/shutdown state return unlock state of the user key + // In the stopping/shutdown state, return unlock state of the user's CE storage. case UserState.STATE_STOPPING: case UserState.STATE_SHUTDOWN: - return StorageManager.isUserKeyUnlocked(userId); + return StorageManager.isCeStorageUnlocked(userId); default: return false; } diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index e4a5a3e0ed00..235843643a0d 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -399,59 +399,6 @@ public final class GameManagerService extends IGameManagerService.Stub { } } - public enum FrameRate { - FPS_DEFAULT(0), - FPS_30(30), - FPS_36(36), - FPS_40(40), - FPS_45(45), - FPS_48(48), - FPS_60(60), - FPS_72(72), - FPS_90(90), - FPS_120(120), - FPS_144(144), - FPS_INVALID(-1); - - public final int fps; - - FrameRate(int fps) { - this.fps = fps; - } - } - - // Turn the raw string to the corresponding fps int. - // Return 0 when disabling, -1 for invalid fps. - static int getFpsInt(String raw) { - // TODO(b/243448953): make sure this translates to proper values based on current display - switch (raw) { - case "30": - return FrameRate.FPS_30.fps; - case "36": - return FrameRate.FPS_36.fps; - case "40": - return FrameRate.FPS_40.fps; - case "45": - return FrameRate.FPS_45.fps; - case "48": - return FrameRate.FPS_48.fps; - case "60": - return FrameRate.FPS_60.fps; - case "72": - return FrameRate.FPS_72.fps; - case "90": - return FrameRate.FPS_90.fps; - case "120": - return FrameRate.FPS_120.fps; - case "144": - return FrameRate.FPS_144.fps; - case "disable": - case "": - return FrameRate.FPS_DEFAULT.fps; - } - return FrameRate.FPS_INVALID.fps; - } - /** * Called by games to communicate the current state to the platform. * @@ -699,7 +646,12 @@ public final class GameManagerService extends IGameManagerService.Stub { } public synchronized int getFps() { - return GameManagerService.getFpsInt(mFps); + try { + final int fpsInt = Integer.parseInt(mFps); + return fpsInt; + } catch (NumberFormatException e) { + return 0; + } } synchronized String getFpsStr() { @@ -739,7 +691,12 @@ public final class GameManagerService extends IGameManagerService.Stub { } android.app.GameModeConfiguration toPublicGameModeConfig() { - int fpsOverride = getFpsInt(mFps); + int fpsOverride; + try { + fpsOverride = Integer.parseInt(mFps); + } catch (NumberFormatException e) { + fpsOverride = 0; + } // TODO(b/243448953): match to proper value in case of display change? fpsOverride = fpsOverride > 0 ? fpsOverride : android.app.GameModeConfiguration.FPS_OVERRIDE_NONE; diff --git a/services/core/java/com/android/server/app/GameManagerShellCommand.java b/services/core/java/com/android/server/app/GameManagerShellCommand.java index 00ff489ee0ff..ab57c4fe837e 100644 --- a/services/core/java/com/android/server/app/GameManagerShellCommand.java +++ b/services/core/java/com/android/server/app/GameManagerShellCommand.java @@ -241,8 +241,10 @@ public class GameManagerShellCommand extends ShellCommand { case "--fps": if (fpsStr == null) { fpsStr = getNextArgRequired(); - if (fpsStr != null && GameManagerService.getFpsInt(fpsStr) == -1) { - pw.println("Invalid frame rate '" + fpsStr + "'"); + try { + Integer.parseInt(fpsStr); + } catch (NumberFormatException e) { + pw.println("Invalid frame rate: '" + fpsStr + "'"); return -1; } } else { @@ -375,8 +377,8 @@ public class GameManagerShellCommand extends ShellCommand { pw.println(" --downscale [0.3|0.35|0.4|0.45|0.5|0.55|0.6|0.65"); pw.println(" |0.7|0.75|0.8|0.85|0.9|disable]: Set app to run at the"); pw.println(" specified scaling ratio."); - pw.println(" --fps [30|45|60|90|120|disable]: Set app to run at the specified fps,"); - pw.println(" if supported."); + pw.println(" --fps: Integer value to set app to run at the specified fps,"); + pw.println(" if supported. 0 to disable."); pw.println(" reset [--mode [2|3|performance|battery] --user <USER_ID>] <PACKAGE_NAME>"); pw.println(" Resets the game mode of the app to device configuration."); pw.println(" This should only be used to reset any override to non custom game mode"); diff --git a/services/core/java/com/android/server/compat/overrides/OWNERS b/services/core/java/com/android/server/compat/overrides/OWNERS index b80f3402c19d..6ca7803a455c 100644 --- a/services/core/java/com/android/server/compat/overrides/OWNERS +++ b/services/core/java/com/android/server/compat/overrides/OWNERS @@ -1,2 +1,2 @@ -tomnatan@google.com +mcarli@google.com mariiasand@google.com diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 4ccc554f1fe1..fa95a348d8d3 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -694,9 +694,9 @@ public class LockSettingsService extends ILockSettings.Stub { return; } - if (isUserKeyUnlocked(userId)) { - // If storage is not locked, the user will be automatically unlocked so there is - // no need to show the notification. + if (isCeStorageUnlocked(userId)) { + // If the user's CE storage is already unlocked, then the user will be automatically + // unlocked, so there is no need to show the notification. return; } @@ -1027,8 +1027,8 @@ public class LockSettingsService extends ILockSettings.Stub { // they did have an SP then their CE key wasn't encrypted by it. // // If this gets interrupted (e.g. by the device powering off), there shouldn't be a - // problem since this will run again on the next boot, and setUserKeyProtection() is - // okay with the key being already protected by the given secret. + // problem since this will run again on the next boot, and setCeStorageProtection() is + // okay with the CE key being already protected by the given secret. if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { for (UserInfo user : mUserManager.getAliveUsers()) { removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); @@ -1063,7 +1063,7 @@ public class LockSettingsService extends ILockSettings.Stub { Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId); return; } - setUserKeyProtection(userId, result.syntheticPassword); + setCeStorageProtection(userId, result.syntheticPassword); } } @@ -2002,11 +2002,11 @@ public class LockSettingsService extends ILockSettings.Stub { mStorage.writeChildProfileLock(profileUserId, ArrayUtils.concat(iv, ciphertext)); } - private void setUserKeyProtection(@UserIdInt int userId, SyntheticPassword sp) { + private void setCeStorageProtection(@UserIdInt int userId, SyntheticPassword sp) { final byte[] secret = sp.deriveFileBasedEncryptionKey(); final long callingId = Binder.clearCallingIdentity(); try { - mStorageManager.setUserKeyProtection(userId, secret); + mStorageManager.setCeStorageProtection(userId, secret); } catch (RemoteException e) { throw new IllegalStateException("Failed to protect CE key for user " + userId, e); } finally { @@ -2014,11 +2014,11 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private boolean isUserKeyUnlocked(int userId) { + private boolean isCeStorageUnlocked(int userId) { try { - return mStorageManager.isUserKeyUnlocked(userId); + return mStorageManager.isCeStorageUnlocked(userId); } catch (RemoteException e) { - Slog.e(TAG, "failed to check user key locked state", e); + Slog.e(TAG, "Error checking whether CE storage is unlocked", e); return false; } } @@ -2029,8 +2029,8 @@ public class LockSettingsService extends ILockSettings.Stub { * This method doesn't throw exceptions because it is called opportunistically whenever a user * is started. Whether it worked or not can be detected by whether the key got unlocked or not. */ - private void unlockUserKey(@UserIdInt int userId, SyntheticPassword sp) { - if (isUserKeyUnlocked(userId)) { + private void unlockCeStorage(@UserIdInt int userId, SyntheticPassword sp) { + if (isCeStorageUnlocked(userId)) { Slogf.d(TAG, "CE storage for user %d is already unlocked", userId); return; } @@ -2038,7 +2038,7 @@ public class LockSettingsService extends ILockSettings.Stub { final String userType = isUserSecure(userId) ? "secured" : "unsecured"; final byte[] secret = sp.deriveFileBasedEncryptionKey(); try { - mStorageManager.unlockUserKey(userId, userInfo.serialNumber, secret); + mStorageManager.unlockCeStorage(userId, userInfo.serialNumber, secret); Slogf.i(TAG, "Unlocked CE storage for %s user %d", userType, userId); } catch (RemoteException e) { Slogf.wtf(TAG, e, "Failed to unlock CE storage for %s user %d", userType, userId); @@ -2051,8 +2051,10 @@ public class LockSettingsService extends ILockSettings.Stub { public void unlockUserKeyIfUnsecured(@UserIdInt int userId) { checkPasswordReadPermission(); synchronized (mSpManager) { - if (isUserKeyUnlocked(userId)) { + if (isCeStorageUnlocked(userId)) { Slogf.d(TAG, "CE storage for user %d is already unlocked", userId); + // This method actually does more than unlock CE storage. However, if CE storage is + // already unlocked, then the other parts must have already been done too. return; } if (isUserSecure(userId)) { @@ -2069,7 +2071,7 @@ public class LockSettingsService extends ILockSettings.Stub { return; } onSyntheticPasswordUnlocked(userId, result.syntheticPassword); - unlockUserKey(userId, result.syntheticPassword); + unlockCeStorage(userId, result.syntheticPassword); } } @@ -2772,7 +2774,7 @@ public class LockSettingsService extends ILockSettings.Stub { final long protectorId = mSpManager.createLskfBasedProtector(getGateKeeperService(), LockscreenCredential.createNone(), sp, userId); setCurrentLskfBasedProtectorId(protectorId, userId); - setUserKeyProtection(userId, sp); + setCeStorageProtection(userId, sp); onSyntheticPasswordCreated(userId, sp); Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId); return sp; @@ -2833,7 +2835,7 @@ public class LockSettingsService extends ILockSettings.Stub { unlockKeystore(userId, sp); - unlockUserKey(userId, sp); + unlockCeStorage(userId, sp); unlockUser(userId); @@ -2897,7 +2899,7 @@ public class LockSettingsService extends ILockSettings.Stub { mSpManager.clearSidForUser(userId); gateKeeperClearSecureUserId(userId); - unlockUserKey(userId, sp); + unlockCeStorage(userId, sp); unlockKeystore(userId, sp); setKeystorePassword(null, userId); removeBiometricsForUser(userId); diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java index a5a934f78420..550ad5d610da 100644 --- a/services/core/java/com/android/server/net/NetworkManagementService.java +++ b/services/core/java/com/android/server/net/NetworkManagementService.java @@ -74,6 +74,7 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.util.DumpUtils; import com.android.internal.util.HexDump; import com.android.modules.utils.build.SdkLevel; +import com.android.net.flags.Flags; import com.android.net.module.util.NetdUtils; import com.android.net.module.util.PermissionUtils; import com.android.server.FgThread; @@ -1059,17 +1060,25 @@ public class NetworkManagementService extends INetworkManagementService.Stub { Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode); return true; } - Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "bandwidthEnableDataSaver"); + Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDataSaverModeEnabled"); try { - final boolean changed = mNetdService.bandwidthEnableDataSaver(enable); - if (changed) { + if (Flags.setDataSaverViaCm()) { + // setDataSaverEnabled throws if it fails to set data saver. + mContext.getSystemService(ConnectivityManager.class) + .setDataSaverEnabled(enable); mDataSaverMode = enable; + return true; } else { - Log.w(TAG, "setDataSaverMode(" + enable + "): netd command silently failed"); + final boolean changed = mNetdService.bandwidthEnableDataSaver(enable); + if (changed) { + mDataSaverMode = enable; + } else { + Log.e(TAG, "setDataSaverMode(" + enable + "): failed to set iptables"); + } + return changed; } - return changed; - } catch (RemoteException e) { - Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e); + } catch (RemoteException | IllegalStateException e) { + Log.e(TAG, "setDataSaverMode(" + enable + "): failed with exception", e); return false; } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); diff --git a/services/core/java/com/android/server/notification/OWNERS b/services/core/java/com/android/server/notification/OWNERS index 6c4dd6d13d92..9f16662fd749 100644 --- a/services/core/java/com/android/server/notification/OWNERS +++ b/services/core/java/com/android/server/notification/OWNERS @@ -1,6 +1,9 @@ -# Bug component: 34005 +# Bug component: 78010 juliacr@google.com yurilin@google.com +aroederer@google.com +matiashe@google.com +valiiftime@google.com jeffdq@google.com dsandler@android.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java index f95f7bc0d165..0803bb662c70 100644 --- a/services/core/java/com/android/server/pm/AppDataHelper.java +++ b/services/core/java/com/android/server/pm/AppDataHelper.java @@ -122,7 +122,7 @@ public class AppDataHelper { StorageManagerInternal.class); for (UserInfo user : umInternal.getUsers(false /*excludeDying*/)) { final int flags; - if (StorageManager.isUserKeyUnlocked(user.id) + if (StorageManager.isCeStorageUnlocked(user.id) && smInternal.isCeStoragePrepared(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (umInternal.isUserRunning(user.id)) { @@ -404,7 +404,7 @@ public class AppDataHelper { // First look for stale data that doesn't belong, and check if things // have changed since we did our last restorecon if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { - if (StorageManager.isFileEncrypted() && !StorageManager.isUserKeyUnlocked(userId)) { + if (StorageManager.isFileEncrypted() && !StorageManager.isCeStorageUnlocked(userId)) { throw new RuntimeException( "Yikes, someone asked us to reconcile CE storage while " + userId + " was still locked; this would have caused massive data loss!"); diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 78f1fa60b69f..723a3ae659c9 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -3538,7 +3538,7 @@ public class ComputerEngine implements Computer { @Override public int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid, @UserIdInt int userId) { - final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId); + final boolean ceStorageUnlocked = StorageManager.isCeStorageUnlocked(userId); final PackageStateInternal ps = getPackageStateInternal(packageName); if (ps == null || shouldFilterApplication(ps, callingUid, userId) || !ps.getUserStateOrDefault(userId).isInstalled()) { @@ -3553,7 +3553,7 @@ public class ComputerEngine implements Computer { return PackageManagerService.PACKAGE_STARTABILITY_FROZEN; } - if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.getPkg())) { + if (!ceStorageUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.getPkg())) { return PackageManagerService.PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED; } return PackageManagerService.PACKAGE_STARTABILITY_OK; diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java index fef53d15c09d..4780ed1950b8 100644 --- a/services/core/java/com/android/server/pm/MovePackageHelper.java +++ b/services/core/java/com/android/server/pm/MovePackageHelper.java @@ -198,7 +198,8 @@ public final class MovePackageHelper { // If we're moving app data around, we need all the users unlocked if (moveCompleteApp) { for (int userId : installedUserIds) { - if (StorageManager.isFileEncrypted() && !StorageManager.isUserKeyUnlocked(userId)) { + if (StorageManager.isFileEncrypted() + && !StorageManager.isCeStorageUnlocked(userId)) { freezer.close(); throw new PackageManagerException(MOVE_FAILED_LOCKED_USER, "User " + userId + " must be unlocked"); diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 6a2ddc8f94b0..ea082cf77987 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -159,6 +159,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (pkgSetting.getPkg().isCoreApp()) { throw new IllegalStateException("Found a core app that's not important"); } + // Use REASON_FIRST_BOOT to query "pm.dexopt.first-boot" for the compiler filter, but + // the reason itself won't make it into the actual compiler reason because it will be + // overridden in otapreopt.cpp. mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.getPkg(), pkgSetting, PackageManagerService.REASON_FIRST_BOOT)); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 20bd56d56945..daf3617be91c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3460,7 +3460,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService UserManagerInternal umInternal = mInjector.getUserManagerInternal(); StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class); final int flags; - if (StorageManager.isUserKeyUnlocked(userId) && smInternal.isCeStoragePrepared(userId)) { + if (StorageManager.isCeStorageUnlocked(userId) && smInternal.isCeStoragePrepared(userId)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (umInternal.isUserRunning(userId)) { flags = StorageManager.FLAG_STORAGE_DE; diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java index 8f8f4376d2cc..89619232eb04 100644 --- a/services/core/java/com/android/server/pm/StorageEventHelper.java +++ b/services/core/java/com/android/server/pm/StorageEventHelper.java @@ -183,7 +183,7 @@ public final class StorageEventHelper extends StorageEventListener { StorageManagerInternal.class); for (UserInfo user : mPm.mUserManager.getUsers(false /* includeDying */)) { final int flags; - if (StorageManager.isUserKeyUnlocked(user.id) + if (StorageManager.isCeStorageUnlocked(user.id) && smInternal.isCeStoragePrepared(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (umInternal.isUserRunning(user.id)) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 7e88e13e1788..e11e226054e3 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1348,7 +1348,7 @@ public class UserManagerService extends IUserManager.Stub { } final boolean needToShowConfirmCredential = !dontAskCredential && mLockPatternUtils.isSecure(userId) - && (!hasUnifiedChallenge || !StorageManager.isUserKeyUnlocked(userId)); + && (!hasUnifiedChallenge || !StorageManager.isCeStorageUnlocked(userId)); if (needToShowConfirmCredential) { if (onlyIfCredentialNotRequired) { return false; @@ -4905,9 +4905,9 @@ public class UserManagerService extends IUserManager.Stub { } } - t.traceBegin("createUserKey"); + t.traceBegin("createUserStorageKeys"); final StorageManager storage = mContext.getSystemService(StorageManager.class); - storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral()); + storage.createUserStorageKeys(userId, userInfo.serialNumber, userInfo.isEphemeral()); t.traceEnd(); // Only prepare DE storage here. CE storage will be prepared later, when the user is @@ -5731,17 +5731,18 @@ public class UserManagerService extends IUserManager.Stub { private void removeUserState(final @UserIdInt int userId) { Slog.i(LOG_TAG, "Removing user state of user " + userId); - // Cleanup lock settings. This must happen before destroyUserKey(), since the user's DE - // storage must still be accessible for the lock settings state to be properly cleaned up. + // Cleanup lock settings. This requires that the user's DE storage still be accessible, so + // this must happen before destroyUserStorageKeys(). mLockPatternUtils.removeUser(userId); // Evict and destroy the user's CE and DE encryption keys. At this point, the user's CE and // DE storage is made inaccessible, except to delete its contents. try { - mContext.getSystemService(StorageManager.class).destroyUserKey(userId); + mContext.getSystemService(StorageManager.class).destroyUserStorageKeys(userId); } catch (IllegalStateException e) { // This may be simply because the user was partially created. - Slog.i(LOG_TAG, "Destroying key for user " + userId + " failed, continuing anyway", e); + Slog.i(LOG_TAG, "Destroying storage keys for user " + userId + + " failed, continuing anyway", e); } // Cleanup package manager settings @@ -6991,9 +6992,9 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mUserStates) { state = mUserStates.get(userId, -1); } - // Special case, in the stopping/shutdown state user key can still be unlocked + // Special case: in the stopping/shutdown state, CE storage can still be unlocked. if (state == UserState.STATE_STOPPING || state == UserState.STATE_SHUTDOWN) { - return StorageManager.isUserKeyUnlocked(userId); + return StorageManager.isCeStorageUnlocked(userId); } return (state == UserState.STATE_RUNNING_UNLOCKING) || (state == UserState.STATE_RUNNING_UNLOCKED); @@ -7010,9 +7011,9 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mUserStates) { state = mUserStates.get(userId, -1); } - // Special case, in the stopping/shutdown state user key can still be unlocked + // Special case: in the stopping/shutdown state, CE storage can still be unlocked. if (state == UserState.STATE_STOPPING || state == UserState.STATE_SHUTDOWN) { - return StorageManager.isUserKeyUnlocked(userId); + return StorageManager.isCeStorageUnlocked(userId); } return state == UserState.STATE_RUNNING_UNLOCKED; } diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java index 7b0fe9a9abc7..a01bac688fbf 100644 --- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java +++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java @@ -266,10 +266,10 @@ public class AppDataRollbackHelper { } /** - * @return {@code true} iff. {@code userId} is locked on an FBE device. + * @return {@code true} iff the credential-encrypted storage for {@code userId} is locked. */ @VisibleForTesting public boolean isUserCredentialLocked(int userId) { - return StorageManager.isFileEncrypted() && !StorageManager.isUserKeyUnlocked(userId); + return StorageManager.isFileEncrypted() && !StorageManager.isCeStorageUnlocked(userId); } } diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java index d958222ea407..9213d96ad4ca 100644 --- a/services/core/java/com/android/server/vcn/VcnContext.java +++ b/services/core/java/com/android/server/vcn/VcnContext.java @@ -18,6 +18,8 @@ package com.android.server.vcn; import android.annotation.NonNull; import android.content.Context; +import android.net.vcn.FeatureFlags; +import android.net.vcn.FeatureFlagsImpl; import android.os.Looper; import java.util.Objects; @@ -31,6 +33,7 @@ public class VcnContext { @NonNull private final Context mContext; @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; + @NonNull private final FeatureFlags mFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -42,6 +45,9 @@ public class VcnContext { mLooper = Objects.requireNonNull(looper, "Missing looper"); mVcnNetworkProvider = Objects.requireNonNull(vcnNetworkProvider, "Missing networkProvider"); mIsInTestMode = isInTestMode; + + // Auto-generated class + mFeatureFlags = new FeatureFlagsImpl(); } @NonNull @@ -63,6 +69,11 @@ public class VcnContext { return mIsInTestMode; } + @NonNull + public FeatureFlags getFeatureFlags() { + return mFeatureFlags; + } + /** * Verifies that the caller is running on the VcnContext Thread. * diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index d480ddb092eb..54c97dd37941 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -1222,6 +1222,14 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) void setSafeModeAlarm() { + final boolean isFlagSafeModeConfigEnabled = mVcnContext.getFeatureFlags().safeModeConfig(); + logVdbg("isFlagSafeModeConfigEnabled " + isFlagSafeModeConfigEnabled); + + if (isFlagSafeModeConfigEnabled && !mConnectionConfig.isSafeModeEnabled()) { + logVdbg("setSafeModeAlarm: safe mode disabled"); + return; + } + logVdbg("Setting safe mode alarm; mCurrentToken: " + mCurrentToken); // Only schedule a NEW alarm if none is already set. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 7addaa265ab2..1c8770b123bb 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -4668,6 +4668,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp scheduleAnimation(); mWmService.mH.post(() -> InputMethodManagerInternal.get().onImeParentChanged()); + } else if (mImeControlTarget != null && mImeControlTarget == mImeLayeringTarget) { + // Even if the IME surface parent is not changed, the layer target belonging to the + // parent may have changes. Then attempt to reassign if the IME control target is + // possible to be the relative layer. + final SurfaceControl lastRelativeLayer = mImeWindowsContainer.getLastRelativeLayer(); + if (lastRelativeLayer != mImeLayeringTarget.mSurfaceControl) { + assignRelativeLayerForIme(getSyncTransaction(), false /* forceUpdate */); + if (lastRelativeLayer != mImeWindowsContainer.getLastRelativeLayer()) { + scheduleAnimation(); + } + } } } diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS index f8c39d0906a0..cd704478aa83 100644 --- a/services/core/java/com/android/server/wm/OWNERS +++ b/services/core/java/com/android/server/wm/OWNERS @@ -18,5 +18,8 @@ rgl@google.com yunfanc@google.com wilsonshih@google.com -per-file BackgroundActivityStartController.java = set noparent -per-file BackgroundActivityStartController.java = brufino@google.com, topjohnwu@google.com, achim@google.com, ogunwale@google.com, louischang@google.com, lus@google.com +# Files related to background activity launches +per-file Background*Start* = set noparent +per-file Background*Start* = file:/BAL_OWNERS +per-file Background*Start* = ogunwale@google.com, louischang@google.com + diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 9a0e47de7873..eba9bf669d47 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -1637,8 +1637,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - if (!StorageManager.isUserKeyUnlocked(mCurrentUser)) { - // Can't launch home on secondary display areas if device is still locked. + if (!StorageManager.isCeStorageUnlocked(mCurrentUser)) { + // Can't launch home on secondary display areas if CE storage is still locked. return false; } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 3063d46208c2..46ca4455f93c 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -6510,11 +6510,11 @@ class Task extends TaskFragment { mActivityType = ACTIVITY_TYPE_STANDARD; } - if (mActivityType != ACTIVITY_TYPE_STANDARD + if (!DisplayContent.alwaysCreateRootTask(tda.getWindowingMode(), mActivityType) && mActivityType != ACTIVITY_TYPE_UNDEFINED) { - // For now there can be only one root task of a particular non-standard activity - // type on a display. So, get that ignoring whatever windowing mode it is - // currently in. + // Only Recents or Standard activity types are allowed to have more than one + // root task on a display, this is independent of whatever windowing mode it + // is currently in. Task rootTask = tda.getRootTask(WINDOWING_MODE_UNDEFINED, mActivityType); if (rootTask != null) { throw new IllegalArgumentException("Root task=" + rootTask + " of activityType=" diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 0152666a830d..4cab3a29f136 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2635,6 +2635,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return mLastLayer; } + SurfaceControl getLastRelativeLayer() { + return mLastRelativeToLayer; + } + protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { if (mSurfaceFreezer.hasLeash()) { // When the freezer has created animation leash parent for the window, set the layer diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index dccacb4d301a..a3403bb3ec39 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -345,7 +345,7 @@ public class UserControllerTest { assertWithMessage("should not have received intents") .that(getActions(mInjector.mSentIntents)).isEmpty(); // TODO(b/140868593): should have received a USER_UNLOCK_MSG message as well, but it doesn't - // because StorageManager.isUserKeyUnlocked(TEST_PRE_CREATED_USER_ID) returns false - to + // because StorageManager.isCeStorageUnlocked(TEST_PRE_CREATED_USER_ID) returns false - to // properly fix it, we'd need to move this class to FrameworksMockingServicesTests so we can // mock static methods (but moving this class would involve changing the presubmit tests, // and the cascade effect goes on...). In fact, a better approach would to not assert the @@ -648,7 +648,7 @@ public class UserControllerTest { // checking. waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS); verify(mInjector.mStorageManagerMock, times(0)) - .lockUserKey(anyInt()); + .lockCeStorage(anyInt()); addForegroundUserAndContinueUserSwitch(TEST_USER_ID2, TEST_USER_ID1, numerOfUserSwitches, true); @@ -663,7 +663,7 @@ public class UserControllerTest { mUserController.finishUserStopped(ussUser1, /* allowDelayedLocking= */ true); waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS); verify(mInjector.mStorageManagerMock, times(1)) - .lockUserKey(TEST_USER_ID); + .lockCeStorage(TEST_USER_ID); } /** @@ -757,7 +757,7 @@ public class UserControllerTest { mUserController.startUser(TEST_USER_ID, USER_START_MODE_BACKGROUND); verify(mInjector.mStorageManagerMock, never()) - .unlockUserKey(eq(TEST_USER_ID), anyInt(), any()); + .unlockCeStorage(eq(TEST_USER_ID), anyInt(), any()); } @Test @@ -1035,7 +1035,7 @@ public class UserControllerTest { mUserController.finishUserStopped(ussUser, delayedLocking); waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS); verify(mInjector.mStorageManagerMock, times(expectLocking ? 1 : 0)) - .lockUserKey(userId); + .lockCeStorage(userId); } private void addForegroundUserAndContinueUserSwitch(int newUserId, int expectedOldUserId, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index fe2ac176949d..f5d50d173466 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -304,17 +304,17 @@ public abstract class BaseLockSettingsServiceTests { doAnswer(invocation -> { Object[] args = invocation.getArguments(); - mStorageManager.unlockUserKey(/* userId= */ (int) args[0], + mStorageManager.unlockCeStorage(/* userId= */ (int) args[0], /* secret= */ (byte[]) args[2]); return null; - }).when(sm).unlockUserKey(anyInt(), anyInt(), any()); + }).when(sm).unlockCeStorage(anyInt(), anyInt(), any()); doAnswer(invocation -> { Object[] args = invocation.getArguments(); - mStorageManager.setUserKeyProtection(/* userId= */ (int) args[0], + mStorageManager.setCeStorageProtection(/* userId= */ (int) args[0], /* secret= */ (byte[]) args[1]); return null; - }).when(sm).setUserKeyProtection(anyInt(), any()); + }).when(sm).setCeStorageProtection(anyInt(), any()); return sm; } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java index 91f3fed01267..c08ad134d74a 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java @@ -24,7 +24,7 @@ public class FakeStorageManager { private final ArrayMap<Integer, byte[]> mUserSecrets = new ArrayMap<>(); - public void setUserKeyProtection(int userId, byte[] secret) { + public void setCeStorageProtection(int userId, byte[] secret) { assertThat(mUserSecrets).doesNotContainKey(userId); mUserSecrets.put(userId, secret); } @@ -35,7 +35,7 @@ public class FakeStorageManager { return secret; } - public void unlockUserKey(int userId, byte[] secret) { + public void unlockCeStorage(int userId, byte[] secret) { assertThat(mUserSecrets.get(userId)).isEqualTo(secret); } } diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java index af144cf49a46..2cdfbffda407 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java @@ -57,6 +57,7 @@ import android.util.ArrayMap; import androidx.test.runner.AndroidJUnit4; import com.android.internal.app.IBatteryStats; +import com.android.net.flags.Flags; import org.junit.After; import org.junit.Before; @@ -263,7 +264,11 @@ public class NetworkManagementServiceTest { verify(mCm).addUidToMeteredNetworkDenyList(TEST_UID); mNMService.setDataSaverModeEnabled(true); - verify(mNetdService).bandwidthEnableDataSaver(true); + if (Flags.setDataSaverViaCm()) { + verify(mCm).setDataSaverEnabled(true); + } else { + verify(mNetdService).bandwidthEnableDataSaver(true); + } mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, false); assertTrue("Should be true since data saver is on and the uid is not allowlisted", @@ -279,7 +284,11 @@ public class NetworkManagementServiceTest { mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false); verify(mCm).removeUidFromMeteredNetworkAllowList(TEST_UID); mNMService.setDataSaverModeEnabled(false); - verify(mNetdService).bandwidthEnableDataSaver(false); + if (Flags.setDataSaverViaCm()) { + verify(mCm).setDataSaverEnabled(false); + } else { + verify(mNetdService).bandwidthEnableDataSaver(false); + } assertFalse("Network should not be restricted when data saver is off", mNMService.isNetworkRestricted(TEST_UID)); } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 3bc6450ae591..b92cc64194e6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -870,7 +870,7 @@ public class RootWindowContainerTests extends WindowTestsBase { new TestDisplayContent.Builder(mAtm, 1000, 1500) .setSystemDecorations(true).build(); - // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false. + // Use invalid user id to let StorageManager.isCeStorageUnlocked() return false. final int currentUser = mRootWindowContainer.mCurrentUser; mRootWindowContainer.mCurrentUser = -1; diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index 3ec6f425a37a..973ab846fa4a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -448,7 +448,6 @@ public class ZOrderingTests extends WindowTestsBase { mDisplayContent.updateImeParent(); // Ime should on top of the popup IME layering target window. - mDisplayContent.assignChildLayers(mTransaction); assertWindowHigher(mImeWindow, popupImeTargetWin); } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index a72f7806d3ea..89ef523c2c71 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -2352,6 +2352,11 @@ public class TelecomManager { * <p> * <b>Note</b>: {@link android.app.Notification.CallStyle} notifications should be posted after * the call is placed in order for the notification to be non-dismissible. + * <p><b>Note</b>: Call Forwarding MMI codes can only be dialed by applications that are + * configured as the user defined default dialer or system dialer role. If a call containing a + * call forwarding MMI code is placed by an application that is not in one of these roles, the + * dialer will be launched with a UI showing the MMI code already populated so that the user can + * confirm the action before the call is placed. * @param address The address to make the call to. * @param extras Bundle of extras to use with the call. */ diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 749ed03b727f..43dab5338e93 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -8770,7 +8770,9 @@ public class CarrierConfigManager { * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_NONE}, * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1024_BIT_MODP}, * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1536_BIT_MODP}, - * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_2048_BIT_MODP} + * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_2048_BIT_MODP}, + * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_3072_BIT_MODP}, + * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_4096_BIT_MODP} */ public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY = KEY_PREFIX + "diffie_hellman_groups_int_array"; @@ -8838,7 +8840,8 @@ public class CarrierConfigManager { /** * List of supported encryption algorithms for child session. Possible values are - * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC} + * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC}, + * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CTR} */ public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = KEY_PREFIX + "supported_child_session_encryption_algorithms_int_array"; diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index a1a39ff173b4..cb3782173dc8 100644 --- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -117,6 +117,16 @@ public class VcnGatewayConnectionConfigTest { return buildTestConfig(UNDERLYING_NETWORK_TEMPLATES); } + // Public for use in VcnGatewayConnectionTest + public static VcnGatewayConnectionConfig.Builder newTestBuilderMinimal() { + final VcnGatewayConnectionConfig.Builder builder = newBuilder(); + for (int caps : EXPOSED_CAPS) { + builder.addExposedCapability(caps); + } + + return builder; + } + private static VcnGatewayConnectionConfig.Builder newBuilder() { // Append a unique identifier to the name prefix to guarantee that all created // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig). @@ -125,6 +135,17 @@ public class VcnGatewayConnectionConfigTest { TUNNEL_CONNECTION_PARAMS); } + private static VcnGatewayConnectionConfig.Builder newBuilderMinimal() { + final VcnGatewayConnectionConfig.Builder builder = + new VcnGatewayConnectionConfig.Builder( + "newBuilderMinimal", TUNNEL_CONNECTION_PARAMS); + for (int caps : EXPOSED_CAPS) { + builder.addExposedCapability(caps); + } + + return builder; + } + private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions( VcnGatewayConnectionConfig.Builder builder, Set<Integer> gatewayOptions, @@ -273,6 +294,7 @@ public class VcnGatewayConnectionConfigTest { assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); assertEquals(MAX_MTU, config.getMaxMtu()); + assertTrue(config.isSafeModeEnabled()); assertFalse( config.hasGatewayOption( @@ -290,6 +312,13 @@ public class VcnGatewayConnectionConfigTest { } @Test + public void testBuilderAndGettersSafeModeDisabled() { + final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build(); + + assertFalse(config.isSafeModeEnabled()); + } + + @Test public void testPersistableBundle() { final VcnGatewayConnectionConfig config = buildTestConfig(); @@ -305,6 +334,13 @@ public class VcnGatewayConnectionConfigTest { } @Test + public void testPersistableBundleSafeModeDisabled() { + final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build(); + + assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle())); + } + + @Test public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() { PersistableBundle configBundle = buildTestConfig().toPersistableBundle(); configBundle.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, null); @@ -411,4 +447,18 @@ public class VcnGatewayConnectionConfigTest { assertEquals(config, configEqual); assertNotEquals(config, configNotEqual); } + + @Test + public void testSafeModeEnableDisableEquality() throws Exception { + final VcnGatewayConnectionConfig config = newBuilderMinimal().build(); + final VcnGatewayConnectionConfig configEqual = newBuilderMinimal().build(); + + assertEquals(config.isSafeModeEnabled(), configEqual.isSafeModeEnabled()); + + final VcnGatewayConnectionConfig configNotEqual = + newBuilderMinimal().enableSafeMode(false).build(); + + assertEquals(config, configEqual); + assertNotEquals(config, configNotEqual); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 302af523a4bd..bf73198d1006 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -75,6 +75,9 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; +import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; +import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; +import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; import com.android.server.vcn.util.MtuUtils; @@ -651,6 +654,74 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifySafeModeStateAndCallbackFired(2 /* invocationCount */, true /* isInSafeMode */); } + private void verifySetSafeModeAlarm( + boolean safeModeEnabledByCaller, + boolean safeModeConfigFlagEnabled, + boolean expectingSafeModeEnabled) + throws Exception { + final VcnGatewayConnectionConfig config = + VcnGatewayConnectionConfigTest.newTestBuilderMinimal() + .enableSafeMode(safeModeEnabledByCaller) + .build(); + final VcnGatewayConnection.Dependencies deps = + mock(VcnGatewayConnection.Dependencies.class); + setUpWakeupMessage( + mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM, deps); + doReturn(safeModeConfigFlagEnabled).when(mFeatureFlags).safeModeConfig(); + + final VcnGatewayConnection connection = + new VcnGatewayConnection( + mVcnContext, + TEST_SUB_GRP, + TEST_SUBSCRIPTION_SNAPSHOT, + config, + mGatewayStatusCallback, + true /* isMobileDataEnabled */, + deps); + + connection.setSafeModeAlarm(); + + final int expectedCallCnt = expectingSafeModeEnabled ? 1 : 0; + verify(deps, times(expectedCallCnt)) + .newWakeupMessage( + eq(mVcnContext), + any(), + eq(VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM), + any()); + } + + @Test + public void testSafeModeEnabled_configFlagEnabled() throws Exception { + verifySetSafeModeAlarm( + true /* safeModeEnabledByCaller */, + true /* safeModeConfigFlagEnabled */, + true /* expectingSafeModeEnabled */); + } + + @Test + public void testSafeModeEnabled_configFlagDisabled() throws Exception { + verifySetSafeModeAlarm( + true /* safeModeEnabledByCaller */, + false /* safeModeConfigFlagEnabled */, + true /* expectingSafeModeEnabled */); + } + + @Test + public void testSafeModeDisabled_configFlagEnabled() throws Exception { + verifySetSafeModeAlarm( + false /* safeModeEnabledByCaller */, + true /* safeModeConfigFlagEnabled */, + false /* expectingSafeModeEnabled */); + } + + @Test + public void testSafeModeDisabled_configFlagDisabled() throws Exception { + verifySetSafeModeAlarm( + false /* safeModeEnabledByCaller */, + false /* safeModeConfigFlagEnabled */, + true /* expectingSafeModeEnabled */); + } + private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() { triggerChildOpened(); mTestLooper.dispatchAll(); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 5efbf598f941..edced87427c8 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -53,6 +53,7 @@ import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionConnectionInfo; +import android.net.vcn.FeatureFlags; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; @@ -165,6 +166,7 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; @NonNull protected final VcnNetworkProvider mVcnNetworkProvider; + @NonNull protected final FeatureFlags mFeatureFlags; @NonNull protected final VcnContext mVcnContext; @NonNull protected final VcnGatewayConnectionConfig mConfig; @NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback; @@ -190,6 +192,7 @@ public class VcnGatewayConnectionTestBase { mContext = mock(Context.class); mTestLooper = new TestLooper(); mVcnNetworkProvider = mock(VcnNetworkProvider.class); + mFeatureFlags = mock(FeatureFlags.class); mVcnContext = mock(VcnContext.class); mConfig = VcnGatewayConnectionConfigTest.buildTestConfig(); mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class); @@ -222,6 +225,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mContext).when(mVcnContext).getContext(); doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); + doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); doReturn(mUnderlyingNetworkController) .when(mDeps) @@ -241,8 +245,15 @@ public class VcnGatewayConnectionTestBase { doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime(); } + protected void setUpWakeupMessage( + @NonNull WakeupMessage msg, + @NonNull String cmdName, + VcnGatewayConnection.Dependencies deps) { + doReturn(msg).when(deps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any()); + } + private void setUpWakeupMessage(@NonNull WakeupMessage msg, @NonNull String cmdName) { - doReturn(msg).when(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any()); + setUpWakeupMessage(msg, cmdName, mDeps); } @Before diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 0d6dc3522d24..ed3e1ac5c39f 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -121,7 +121,6 @@ cc_library_host_static { "link/AutoVersioner.cpp", "link/ManifestFixer.cpp", "link/NoDefaultResourceRemover.cpp", - "link/ProductFilter.cpp", "link/PrivateAttributeMover.cpp", "link/ReferenceLinker.cpp", "link/ResourceExcluder.cpp", @@ -134,6 +133,7 @@ cc_library_host_static { "optimize/ResourceFilter.cpp", "optimize/Obfuscator.cpp", "optimize/VersionCollapser.cpp", + "process/ProductFilter.cpp", "process/SymbolTable.cpp", "split/TableSplitter.cpp", "text/Printer.cpp", diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 03f9715fb265..bb7b13a71412 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -45,6 +45,7 @@ #include "io/StringStream.h" #include "io/Util.h" #include "io/ZipArchive.h" +#include "process/ProductFilter.h" #include "trace/TraceBuffer.h" #include "util/Files.h" #include "util/Util.h" @@ -179,6 +180,15 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options, if (!res_parser.Parse(&xml_parser)) { return false; } + + if (options.product_.has_value()) { + if (!ProductFilter({*options.product_}, /* remove_default_config_values = */ true) + .Consume(context, &table)) { + context->GetDiagnostics()->Error(android::DiagMessage(path_data.source) + << "failed to filter product"); + return false; + } + } } if (options.pseudolocalize && translatable_file) { diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h index 14a730a1b1a0..984d8901ac56 100644 --- a/tools/aapt2/cmd/Compile.h +++ b/tools/aapt2/cmd/Compile.h @@ -42,6 +42,7 @@ struct CompileOptions { // See comments on aapt::ResourceParserOptions. bool preserve_visibility_of_styleables = false; bool verbose = false; + std::optional<std::string> product_; }; /** Parses flags and compiles resources to be used in linking. */ @@ -76,6 +77,10 @@ class CompileCommand : public Command { AddOptionalFlag("--source-path", "Sets the compiled resource file source file path to the given string.", &options_.source_path); + AddOptionalFlag("--filter-product", + "Leave only resources specific to the given product. All " + "other resources (including defaults) are removed.", + &options_.product_); } int Action(const std::vector<std::string>& args) override; diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 97404fc69af2..f00be3688597 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -66,6 +66,7 @@ #include "optimize/ResourceDeduper.h" #include "optimize/VersionCollapser.h" #include "process/IResourceTableConsumer.h" +#include "process/ProductFilter.h" #include "process/SymbolTable.h" #include "split/TableSplitter.h" #include "trace/TraceBuffer.h" @@ -2127,7 +2128,7 @@ class Linker { << "can't select products when building static library"); } } else { - ProductFilter product_filter(options_.products); + ProductFilter product_filter(options_.products, /* remove_default_config_values = */ false); if (!product_filter.Consume(context_, &final_table_)) { context_->GetDiagnostics()->Error(android::DiagMessage() << "failed stripping products"); return 1; diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 1b1e93bd480a..a08f385b2270 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -323,6 +323,7 @@ class LinkCommand : public Command { "should only be used together with the --static-lib flag.", &options_.merge_only); AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); + AddOptionalFlagList("--feature-flags", "Placeholder, to be implemented.", &feature_flags_args_); } int Action(const std::vector<std::string>& args) override; @@ -347,6 +348,7 @@ class LinkCommand : public Command { std::optional<std::string> stable_id_file_path_; std::vector<std::string> split_args_; std::optional<std::string> trace_folder_; + std::vector<std::string> feature_flags_args_; }; }// namespace aapt diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h index 44cd276f77a2..18165f7d489f 100644 --- a/tools/aapt2/link/Linkers.h +++ b/tools/aapt2/link/Linkers.h @@ -20,12 +20,12 @@ #include <set> #include <unordered_set> +#include "Resource.h" +#include "SdkConstants.h" #include "android-base/macros.h" +#include "android-base/result.h" #include "androidfw/ConfigDescription.h" #include "androidfw/StringPiece.h" - -#include "Resource.h" -#include "SdkConstants.h" #include "process/IResourceTableConsumer.h" #include "xml/XmlDom.h" @@ -92,28 +92,6 @@ class PrivateAttributeMover : public IResourceTableConsumer { DISALLOW_COPY_AND_ASSIGN(PrivateAttributeMover); }; -class ResourceConfigValue; - -class ProductFilter : public IResourceTableConsumer { - public: - using ResourceConfigValueIter = std::vector<std::unique_ptr<ResourceConfigValue>>::iterator; - - explicit ProductFilter(std::unordered_set<std::string> products) : products_(products) { - } - - ResourceConfigValueIter SelectProductToKeep(const ResourceNameRef& name, - const ResourceConfigValueIter begin, - const ResourceConfigValueIter end, - android::IDiagnostics* diag); - - bool Consume(IAaptContext* context, ResourceTable* table) override; - - private: - DISALLOW_COPY_AND_ASSIGN(ProductFilter); - - std::unordered_set<std::string> products_; -}; - // Removes namespace nodes and URI information from the XmlResource. // // Once an XmlResource is processed by this consumer, it is no longer able to have its attributes diff --git a/tools/aapt2/link/ProductFilter.cpp b/tools/aapt2/process/ProductFilter.cpp index 9544986fda76..0b1c0a6adb51 100644 --- a/tools/aapt2/link/ProductFilter.cpp +++ b/tools/aapt2/process/ProductFilter.cpp @@ -14,16 +14,18 @@ * limitations under the License. */ -#include "link/Linkers.h" +#include "process/ProductFilter.h" + +#include <algorithm> #include "ResourceTable.h" #include "trace/TraceBuffer.h" namespace aapt { -ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep( - const ResourceNameRef& name, const ResourceConfigValueIter begin, - const ResourceConfigValueIter end, android::IDiagnostics* diag) { +std::optional<ProductFilter::ResourceConfigValueIter> ProductFilter::SelectProductToKeep( + const ResourceNameRef& name, ResourceConfigValueIter begin, ResourceConfigValueIter end, + android::IDiagnostics* diag) { ResourceConfigValueIter default_product_iter = end; ResourceConfigValueIter selected_product_iter = end; @@ -36,12 +38,11 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep( << "selection of product '" << config_value->product << "' for resource " << name << " is ambiguous"); - ResourceConfigValue* previously_selected_config_value = - selected_product_iter->get(); + ResourceConfigValue* previously_selected_config_value = selected_product_iter->get(); diag->Note(android::DiagMessage(previously_selected_config_value->value->GetSource()) << "product '" << previously_selected_config_value->product << "' is also a candidate"); - return end; + return std::nullopt; } // Select this product. @@ -54,11 +55,10 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep( diag->Error(android::DiagMessage(config_value->value->GetSource()) << "multiple default products defined for resource " << name); - ResourceConfigValue* previously_default_config_value = - default_product_iter->get(); + ResourceConfigValue* previously_default_config_value = default_product_iter->get(); diag->Note(android::DiagMessage(previously_default_config_value->value->GetSource()) << "default product also defined here"); - return end; + return std::nullopt; } // Mark the default. @@ -66,9 +66,16 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep( } } + if (remove_default_config_values_) { + // If we are leaving only a specific product, return early here instead of selecting the default + // value. Returning end here will cause this value set to be skipped, and will be removed with + // ClearEmptyValues method. + return selected_product_iter; + } + if (default_product_iter == end) { diag->Error(android::DiagMessage() << "no default product defined for resource " << name); - return end; + return std::nullopt; } if (selected_product_iter == end) { @@ -89,20 +96,27 @@ bool ProductFilter::Consume(IAaptContext* context, ResourceTable* table) { ResourceConfigValueIter start_range_iter = iter; while (iter != entry->values.end()) { ++iter; - if (iter == entry->values.end() || - (*iter)->config != (*start_range_iter)->config) { + if (iter == entry->values.end() || (*iter)->config != (*start_range_iter)->config) { // End of the array, or we saw a different config, // so this must be the end of a range of products. // Select the product to keep from the set of products defined. ResourceNameRef name(pkg->name, type->named_type, entry->name); - auto value_to_keep = SelectProductToKeep( - name, start_range_iter, iter, context->GetDiagnostics()); - if (value_to_keep == iter) { + auto value_to_keep = + SelectProductToKeep(name, start_range_iter, iter, context->GetDiagnostics()); + if (!value_to_keep.has_value()) { // An error occurred, we could not pick a product. error = true; - } else { + } else if (auto val = value_to_keep.value(); val != iter) { // We selected a product to keep. Move it to the new array. - new_values.push_back(std::move(*value_to_keep)); + if (remove_default_config_values_) { + // We are filtering values with the given product. The selected value here will be + // a new default value, and all other values will be removed. + new_values.push_back( + std::make_unique<ResourceConfigValue>((*val)->config, android::StringPiece{})); + new_values.back()->value = std::move((*val)->value); + } else { + new_values.push_back(std::move(*val)); + } } // Start the next range of products. @@ -115,7 +129,27 @@ bool ProductFilter::Consume(IAaptContext* context, ResourceTable* table) { } } } + + if (remove_default_config_values_) { + ClearEmptyValues(table); + } + return !error; } +void ProductFilter::ClearEmptyValues(ResourceTable* table) { + // Clear any empty packages/types/entries, as remove_default_config_values_ may remove an entire + // value set. + CHECK(remove_default_config_values_) + << __func__ << " should only be called when remove_default_config_values_ is set"; + + for (auto& pkg : table->packages) { + for (auto& type : pkg->types) { + std::erase_if(type->entries, [](auto& entry) { return entry->values.empty(); }); + } + std::erase_if(pkg->types, [](auto& type) { return type->entries.empty(); }); + } + std::erase_if(table->packages, [](auto& package) { return package->types.empty(); }); +} + } // namespace aapt diff --git a/tools/aapt2/process/ProductFilter.h b/tools/aapt2/process/ProductFilter.h new file mode 100644 index 000000000000..0ec2f00863fc --- /dev/null +++ b/tools/aapt2/process/ProductFilter.h @@ -0,0 +1,65 @@ +#pragma once + +#include <memory> +#include <optional> +#include <string> +#include <unordered_set> +#include <utility> +#include <vector> + +#include "Resource.h" +#include "android-base/macros.h" +#include "androidfw/ConfigDescription.h" +#include "androidfw/IDiagnostics.h" +#include "process/IResourceTableConsumer.h" + +namespace aapt { + +class ResourceConfigValue; + +class ProductFilter : public IResourceTableConsumer { + public: + using ResourceConfigValueIter = std::vector<std::unique_ptr<ResourceConfigValue>>::iterator; + + // Setting remove_default_config_values will remove all values other than + // specified product, including default. For example, if the following table + // + // <string name="foo" product="default">foo_default</string> + // <string name="foo" product="tablet">foo_tablet</string> + // <string name="bar">bar</string> + // + // is consumed with tablet, it will result in + // + // <string name="foo">foo_tablet</string> + // + // removing foo_default and bar. This option is to generate an RRO package + // with given product. + explicit ProductFilter(std::unordered_set<std::string> products, + bool remove_default_config_values) + : products_(std::move(products)), + remove_default_config_values_(remove_default_config_values) { + } + + bool Consume(IAaptContext* context, ResourceTable* table) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ProductFilter); + + // SelectProductToKeep returns an iterator for the selected value. + // + // Returns std::nullopt in case of failure (e.g. ambiguous values, missing or duplicated default + // values). + // Returns `end` if keep_as_default_product is set and no value for the specified product was + // found. + std::optional<ResourceConfigValueIter> SelectProductToKeep(const ResourceNameRef& name, + ResourceConfigValueIter begin, + ResourceConfigValueIter end, + android::IDiagnostics* diag); + + void ClearEmptyValues(ResourceTable* table); + + std::unordered_set<std::string> products_; + bool remove_default_config_values_; +}; + +} // namespace aapt diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/process/ProductFilter_test.cpp index 2cb9afa05cad..27a82dcc3453 100644 --- a/tools/aapt2/link/ProductFilter_test.cpp +++ b/tools/aapt2/process/ProductFilter_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "link/Linkers.h" +#include "process/ProductFilter.h" #include "test/Test.h" @@ -57,17 +57,15 @@ TEST(ProductFilterTest, SelectTwoProducts) { .Build(), context->GetDiagnostics())); - ProductFilter filter({"tablet"}); + ProductFilter filter({"tablet"}, /* remove_default_config_values = */ false); ASSERT_TRUE(filter.Consume(context.get(), &table)); - EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>( - &table, "android:string/one", land, "")); - EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>( - &table, "android:string/one", land, "tablet")); - EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>( - &table, "android:string/one", port, "")); - EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>( - &table, "android:string/one", port, "tablet")); + EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>(&table, "android:string/one", land, "")); + EXPECT_NE(nullptr, + test::GetValueForConfigAndProduct<Id>(&table, "android:string/one", land, "tablet")); + EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>(&table, "android:string/one", port, "")); + EXPECT_NE(nullptr, + test::GetValueForConfigAndProduct<Id>(&table, "android:string/one", port, "tablet")); } TEST(ProductFilterTest, SelectDefaultProduct) { @@ -88,15 +86,15 @@ TEST(ProductFilterTest, SelectDefaultProduct) { context->GetDiagnostics())); ; - ProductFilter filter(std::unordered_set<std::string>{}); + ProductFilter filter(std::unordered_set<std::string>{}, + /* remove_default_config_values = */ false); ASSERT_TRUE(filter.Consume(context.get(), &table)); - EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>( - &table, "android:string/one", - ConfigDescription::DefaultConfig(), "")); - EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>( - &table, "android:string/one", - ConfigDescription::DefaultConfig(), "tablet")); + EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>(&table, "android:string/one", + ConfigDescription::DefaultConfig(), "")); + EXPECT_EQ(nullptr, + test::GetValueForConfigAndProduct<Id>(&table, "android:string/one", + ConfigDescription::DefaultConfig(), "tablet")); } TEST(ProductFilterTest, FailOnAmbiguousProduct) { @@ -123,7 +121,7 @@ TEST(ProductFilterTest, FailOnAmbiguousProduct) { .Build(), context->GetDiagnostics())); - ProductFilter filter({"tablet", "no-sdcard"}); + ProductFilter filter({"tablet", "no-sdcard"}, /* remove_default_config_values = */ false); ASSERT_FALSE(filter.Consume(context.get(), &table)); } @@ -144,8 +142,67 @@ TEST(ProductFilterTest, FailOnMultipleDefaults) { .Build(), context->GetDiagnostics())); - ProductFilter filter(std::unordered_set<std::string>{}); + ProductFilter filter(std::unordered_set<std::string>{}, + /* remove_default_config_values = */ false); ASSERT_FALSE(filter.Consume(context.get(), &table)); } +TEST(ProductFilterTest, RemoveDefaultConfigValues) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + + const ConfigDescription land = test::ParseConfigOrDie("land"); + const ConfigDescription port = test::ParseConfigOrDie("port"); + + ResourceTable table; + ASSERT_TRUE(table.AddResource( + NewResourceBuilder(test::ParseNameOrDie("android:string/one")) + .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/default.xml")).Build(), + land) + .Build(), + context->GetDiagnostics())); + + ASSERT_TRUE(table.AddResource( + NewResourceBuilder(test::ParseNameOrDie("android:string/one")) + .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/tablet.xml")).Build(), + land, "tablet") + .Build(), + context->GetDiagnostics())); + + ASSERT_TRUE(table.AddResource( + NewResourceBuilder(test::ParseNameOrDie("android:string/two")) + .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/default.xml")).Build(), + land) + .Build(), + context->GetDiagnostics())); + + ASSERT_TRUE(table.AddResource( + NewResourceBuilder(test::ParseNameOrDie("android:string/one")) + .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/default.xml")).Build(), + port) + .Build(), + context->GetDiagnostics())); + + ASSERT_TRUE(table.AddResource( + NewResourceBuilder(test::ParseNameOrDie("android:string/one")) + .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/tablet.xml")).Build(), + port, "tablet") + .Build(), + context->GetDiagnostics())); + + ASSERT_TRUE(table.AddResource( + NewResourceBuilder(test::ParseNameOrDie("android:string/two")) + .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/default.xml")).Build(), + port) + .Build(), + context->GetDiagnostics())); + + ProductFilter filter({"tablet"}, /* remove_default_config_values = */ true); + ASSERT_TRUE(filter.Consume(context.get(), &table)); + + EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>(&table, "android:string/one", land, "")); + EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>(&table, "android:string/two", land, "")); + EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>(&table, "android:string/one", port, "")); + EXPECT_EQ(nullptr, test::GetValueForConfigAndProduct<Id>(&table, "android:string/two", port, "")); +} + } // namespace aapt diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt index a20266a9b140..28eab8f62e74 100644 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt +++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt @@ -20,7 +20,6 @@ import com.android.tools.lint.client.api.IssueRegistry import com.android.tools.lint.client.api.Vendor import com.android.tools.lint.detector.api.CURRENT_API import com.google.android.lint.aidl.EnforcePermissionDetector -import com.google.android.lint.aidl.EnforcePermissionHelperDetector import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector import com.google.auto.service.AutoService @@ -30,7 +29,8 @@ class AndroidGlobalIssueRegistry : IssueRegistry() { override val issues = listOf( EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION, EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION, - EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER, + EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER, + EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION, SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT, ) @@ -45,4 +45,4 @@ class AndroidGlobalIssueRegistry : IssueRegistry() { feedbackUrl = "http://b/issues/new?component=315013", contact = "repsonsible-apis@google.com" ) -}
\ No newline at end of file +} diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt index 0baac2c7aacf..a74400d3c0b3 100644 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt +++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt @@ -30,29 +30,34 @@ import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner +import com.google.android.lint.findCallExpression import com.intellij.psi.PsiAnnotation import com.intellij.psi.PsiArrayInitializerMemberValue import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod -import org.jetbrains.uast.UAnnotation +import org.jetbrains.uast.UBlockExpression +import org.jetbrains.uast.UDeclarationsExpression import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression import org.jetbrains.uast.UMethod -import org.jetbrains.uast.toUElement +import org.jetbrains.uast.skipParenthesizedExprDown + +import java.util.EnumSet /** - * Lint Detector that ensures that any method overriding a method annotated - * with @EnforcePermission is also annotated with the exact same annotation. - * The intent is to surface the effective permission checks to the service - * implementations. + * Lint Detector that ensures consistency when using the @EnforcePermission + * annotation. Multiple verifications are implemented: * - * This is done with 2 mechanisms: * 1. Visit any annotation usage, to ensure that any derived class will have - * the correct annotation on each methods. This is for the top to bottom - * propagation. - * 2. Visit any annotation, to ensure that if a method is annotated, it has + * the correct annotation on each methods. Even if the subclass does not + * have the annotation, visitAnnotationUsage will be called which allows us + * to capture the issue. + * 2. Visit any method, to ensure that if a method is annotated, it has * its ancestor also annotated. This is to avoid having an annotation on a * Java method without the corresponding annotation on the AIDL interface. + * 3. When annotated, ensures that the first instruction is to call the helper + * method (or the parent helper). */ class EnforcePermissionDetector : Detector(), SourceCodeScanner { @@ -60,9 +65,8 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { return listOf(ANNOTATION_ENFORCE_PERMISSION) } - override fun getApplicableUastTypes(): List<Class<out UElement>> { - return listOf(UAnnotation::class.java) - } + override fun getApplicableUastTypes(): List<Class<out UElement?>> = + listOf(UMethod::class.java) private fun annotationValueGetChildren(elem: PsiElement): Array<PsiElement> { if (elem is PsiArrayInitializerMemberValue) @@ -121,11 +125,6 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { overriddenMethod: PsiMethod, checkEquivalence: Boolean = true ) { - // If method is not from a Stub subclass, this method shouldn't use @EP at all. - // This is handled by EnforcePermissionHelperDetector. - if (!isContainedInSubclassOfStub(context, overridingMethod.toUElement() as? UMethod)) { - return - } val overridingAnnotation = overridingMethod.getAnnotation(ANNOTATION_ENFORCE_PERMISSION) val overriddenAnnotation = overriddenMethod.getAnnotation(ANNOTATION_ENFORCE_PERMISSION) val location = context.getLocation(element) @@ -161,40 +160,102 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { ) { if (usageInfo.type == AnnotationUsageType.METHOD_OVERRIDE && annotationInfo.origin == AnnotationOrigin.METHOD) { + /* Ignore implementations that are not a sub-class of Stub (i.e., Proxy). */ + val uMethod = element as? UMethod ?: return + if (!isContainedInSubclassOfStub(context, uMethod)) { + return + } val overridingMethod = element.sourcePsi as PsiMethod val overriddenMethod = usageInfo.referenced as PsiMethod compareMethods(context, element, overridingMethod, overriddenMethod) } } - override fun createUastHandler(context: JavaContext): UElementHandler { - return object : UElementHandler() { - override fun visitAnnotation(node: UAnnotation) { - if (node.qualifiedName != ANNOTATION_ENFORCE_PERMISSION) { - return - } - val method = node.uastParent as? UMethod ?: return - val overridingMethod = method as PsiMethod - val parents = overridingMethod.findSuperMethods() - for (overriddenMethod in parents) { - // The equivalence check can be skipped, if both methods are - // annotated, it will be verified by visitAnnotationUsage. - compareMethods(context, method, overridingMethod, - overriddenMethod, checkEquivalence = false) - } + override fun createUastHandler(context: JavaContext): UElementHandler = AidlStubHandler(context) + + private inner class AidlStubHandler(val context: JavaContext) : UElementHandler() { + override fun visitMethod(node: UMethod) { + if (context.evaluator.isAbstract(node)) return + if (!node.hasAnnotation(ANNOTATION_ENFORCE_PERMISSION)) return + + if (!isContainedInSubclassOfStub(context, node)) { + context.report( + ISSUE_MISUSING_ENFORCE_PERMISSION, + node, + context.getLocation(node), + "The class of ${node.name} does not inherit from an AIDL generated Stub class" + ) + return + } + + /* Check that we are connected to the super class */ + val overridingMethod = node as PsiMethod + val parents = overridingMethod.findSuperMethods() + for (overriddenMethod in parents) { + // The equivalence check can be skipped, if both methods are + // annotated, it will be verified by visitAnnotationUsage. + compareMethods(context, node, overridingMethod, + overriddenMethod, checkEquivalence = false) + } + + /* Check that the helper is called as a first instruction */ + val targetExpression = getHelperMethodCallSourceString(node) + val message = + "Method must start with $targetExpression or super.${node.name}(), if applicable" + + val firstExpression = (node.uastBody as? UBlockExpression) + ?.expressions?.firstOrNull() + + if (firstExpression == null) { + context.report( + ISSUE_ENFORCE_PERMISSION_HELPER, + context.getLocation(node), + message, + ) + return + } + + val firstExpressionSource = firstExpression.skipParenthesizedExprDown() + .asSourceString() + .filterNot(Char::isWhitespace) + + if (firstExpressionSource != targetExpression && + firstExpressionSource != "super.$targetExpression") { + // calling super.<methodName>() is also legal + val directSuper = context.evaluator.getSuperMethod(node) + val firstCall = findCallExpression(firstExpression)?.resolve() + if (directSuper != null && firstCall == directSuper) return + + val locationTarget = getLocationTarget(firstExpression) + val expressionLocation = context.getLocation(locationTarget) + + context.report( + ISSUE_ENFORCE_PERMISSION_HELPER, + context.getLocation(node), + message, + getHelperMethodFix(node, expressionLocation), + ) } } } companion object { + + private const val HELPER_SUFFIX = "_enforcePermission" + val EXPLANATION = """ - The @EnforcePermission annotation is used to indicate that the underlying binder code - has already verified the caller's permissions before calling the appropriate method. The - verification code is usually generated by the AIDL compiler, which also takes care of - annotating the generated Java code. + The @EnforcePermission annotation is used to delegate the verification of the caller's + permissions to a generated AIDL method. In order to surface that information to platform developers, the same annotation must be used on the implementation class or methods. + + The @EnforcePermission annotation can only be used on methods whose class extends from + the Stub class generated by the AIDL compiler. When @EnforcePermission is applied, the + AIDL compiler generates a Stub method to do the permission check called yourMethodName$HELPER_SUFFIX. + + yourMethodName$HELPER_SUFFIX must be executed before any other operation. To do that, you can + either call it directly, or call it indirectly via super.yourMethodName(). """ val ISSUE_MISSING_ENFORCE_PERMISSION: Issue = Issue.create( @@ -206,7 +267,7 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { severity = Severity.ERROR, implementation = Implementation( EnforcePermissionDetector::class.java, - Scope.JAVA_FILE_SCOPE + EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) ) ) @@ -219,8 +280,47 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { severity = Severity.ERROR, implementation = Implementation( EnforcePermissionDetector::class.java, - Scope.JAVA_FILE_SCOPE + EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) + ) + ) + + val ISSUE_ENFORCE_PERMISSION_HELPER: Issue = Issue.create( + id = "MissingEnforcePermissionHelper", + briefDescription = """Missing permission-enforcing method call in AIDL method + |annotated with @EnforcePermission""".trimMargin(), + explanation = EXPLANATION, + category = Category.SECURITY, + priority = 6, + severity = Severity.ERROR, + implementation = Implementation( + EnforcePermissionDetector::class.java, + EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) + ) + ) + + val ISSUE_MISUSING_ENFORCE_PERMISSION: Issue = Issue.create( + id = "MisusingEnforcePermissionAnnotation", + briefDescription = "@EnforcePermission cannot be used here", + explanation = EXPLANATION, + category = Category.SECURITY, + priority = 6, + severity = Severity.ERROR, + implementation = Implementation( + EnforcePermissionDetector::class.java, + EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) ) ) + + /** + * handles an edge case with UDeclarationsExpression, where sourcePsi is null, + * resulting in an incorrect Location if used directly + */ + private fun getLocationTarget(firstExpression: UExpression): PsiElement? { + if (firstExpression.sourcePsi != null) return firstExpression.sourcePsi + if (firstExpression is UDeclarationsExpression) { + return firstExpression.declarations.firstOrNull()?.sourcePsi + } + return null + } } } diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt deleted file mode 100644 index df13af516514..000000000000 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.lint.aidl - -import com.android.tools.lint.client.api.UElementHandler -import com.android.tools.lint.detector.api.Category -import com.android.tools.lint.detector.api.Detector -import com.android.tools.lint.detector.api.Implementation -import com.android.tools.lint.detector.api.Issue -import com.android.tools.lint.detector.api.JavaContext -import com.android.tools.lint.detector.api.Scope -import com.android.tools.lint.detector.api.Severity -import com.android.tools.lint.detector.api.SourceCodeScanner -import com.google.android.lint.findCallExpression -import com.intellij.psi.PsiElement -import org.jetbrains.uast.UBlockExpression -import org.jetbrains.uast.UDeclarationsExpression -import org.jetbrains.uast.UElement -import org.jetbrains.uast.UExpression -import org.jetbrains.uast.UMethod -import org.jetbrains.uast.skipParenthesizedExprDown - -class EnforcePermissionHelperDetector : Detector(), SourceCodeScanner { - override fun getApplicableUastTypes(): List<Class<out UElement?>> = - listOf(UMethod::class.java) - - override fun createUastHandler(context: JavaContext): UElementHandler = AidlStubHandler(context) - - private inner class AidlStubHandler(val context: JavaContext) : UElementHandler() { - override fun visitMethod(node: UMethod) { - if (context.evaluator.isAbstract(node)) return - if (!node.hasAnnotation(ANNOTATION_ENFORCE_PERMISSION)) return - - if (!isContainedInSubclassOfStub(context, node)) { - context.report( - ISSUE_MISUSING_ENFORCE_PERMISSION, - node, - context.getLocation(node), - "The class of ${node.name} does not inherit from an AIDL generated Stub class" - ) - return - } - - val targetExpression = getHelperMethodCallSourceString(node) - val message = - "Method must start with $targetExpression or super.${node.name}(), if applicable" - - val firstExpression = (node.uastBody as? UBlockExpression) - ?.expressions?.firstOrNull() - - if (firstExpression == null) { - context.report( - ISSUE_ENFORCE_PERMISSION_HELPER, - context.getLocation(node), - message, - ) - return - } - - val firstExpressionSource = firstExpression.skipParenthesizedExprDown() - .asSourceString() - .filterNot(Char::isWhitespace) - - if (firstExpressionSource != targetExpression && - firstExpressionSource != "super.$targetExpression") { - // calling super.<methodName>() is also legal - val directSuper = context.evaluator.getSuperMethod(node) - val firstCall = findCallExpression(firstExpression)?.resolve() - if (directSuper != null && firstCall == directSuper) return - - val locationTarget = getLocationTarget(firstExpression) - val expressionLocation = context.getLocation(locationTarget) - - context.report( - ISSUE_ENFORCE_PERMISSION_HELPER, - context.getLocation(node), - message, - getHelperMethodFix(node, expressionLocation), - ) - } - } - } - - companion object { - private const val HELPER_SUFFIX = "_enforcePermission" - - private const val EXPLANATION = """ - The @EnforcePermission annotation can only be used on methods whose class extends from - the Stub class generated by the AIDL compiler. When @EnforcePermission is applied, the - AIDL compiler generates a Stub method to do the permission check called yourMethodName$HELPER_SUFFIX. - - yourMethodName$HELPER_SUFFIX must be executed before any other operation. To do that, you can - either call it directly, or call it indirectly via super.yourMethodName(). - """ - - val ISSUE_ENFORCE_PERMISSION_HELPER: Issue = Issue.create( - id = "MissingEnforcePermissionHelper", - briefDescription = """Missing permission-enforcing method call in AIDL method - |annotated with @EnforcePermission""".trimMargin(), - explanation = EXPLANATION, - category = Category.SECURITY, - priority = 6, - severity = Severity.ERROR, - implementation = Implementation( - EnforcePermissionHelperDetector::class.java, - Scope.JAVA_FILE_SCOPE - ) - ) - - val ISSUE_MISUSING_ENFORCE_PERMISSION: Issue = Issue.create( - id = "MisusingEnforcePermissionAnnotation", - briefDescription = "@EnforcePermission cannot be used here", - explanation = EXPLANATION, - category = Category.SECURITY, - priority = 6, - severity = Severity.ERROR, - implementation = Implementation( - EnforcePermissionDetector::class.java, - Scope.JAVA_FILE_SCOPE - ) - ) - - /** - * handles an edge case with UDeclarationsExpression, where sourcePsi is null, - * resulting in an incorrect Location if used directly - */ - private fun getLocationTarget(firstExpression: UExpression): PsiElement? { - if (firstExpression.sourcePsi != null) return firstExpression.sourcePsi - if (firstExpression is UDeclarationsExpression) { - return firstExpression.declarations.firstOrNull()?.sourcePsi - } - return null - } - } -} diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt index 5a63bb4084d2..3ef02f865355 100644 --- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt +++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt @@ -25,10 +25,10 @@ import com.android.tools.lint.detector.api.Issue @Suppress("UnstableApiUsage") class EnforcePermissionHelperDetectorCodegenTest : LintDetectorTest() { - override fun getDetector(): Detector = EnforcePermissionHelperDetector() + override fun getDetector(): Detector = EnforcePermissionDetector() override fun getIssues(): List<Issue> = listOf( - EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER + EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER ) override fun lint(): TestLintTask = super.lint().allowMissingSdk(true) diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt index 10a6e1da91dc..64e2bfbad7bb 100644 --- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt +++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt @@ -20,10 +20,10 @@ import com.android.tools.lint.checks.infrastructure.LintDetectorTest import com.android.tools.lint.checks.infrastructure.TestLintTask class EnforcePermissionHelperDetectorTest : LintDetectorTest() { - override fun getDetector() = EnforcePermissionHelperDetector() + override fun getDetector() = EnforcePermissionDetector() override fun getIssues() = listOf( - EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER, - EnforcePermissionHelperDetector.ISSUE_MISUSING_ENFORCE_PERMISSION + EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER, + EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION ) override fun lint(): TestLintTask = super.lint().allowMissingSdk() |