diff options
501 files changed, 7459 insertions, 5448 deletions
diff --git a/Android.bp b/Android.bp index 084c9f51d12e..c5d557c04472 100644 --- a/Android.bp +++ b/Android.bp @@ -67,6 +67,7 @@ filegroup { name: "framework-non-updatable-sources", srcs: [ // Java/AIDL sources under frameworks/base + ":framework-annotations", ":framework-blobstore-sources", ":framework-core-sources", ":framework-drm-sources", @@ -210,6 +211,7 @@ java_library { "apex_aidl_interface-java", "framework-protos", "updatable-driver-protos", + "ota_metadata_proto_java", "android.hidl.base-V1.0-java", "android.hardware.cas-V1.0-java", "android.hardware.cas-V1.1-java", @@ -341,46 +343,6 @@ platform_compat_config { } filegroup { - name: "framework-annotations", - srcs: [ - "core/java/android/annotation/AnyThread.java", - "core/java/android/annotation/AppIdInt.java", - "core/java/android/annotation/BytesLong.java", - "core/java/android/annotation/CallbackExecutor.java", - "core/java/android/annotation/CallSuper.java", - "core/java/android/annotation/CheckResult.java", - "core/java/android/annotation/CurrentTimeMillisLong.java", - "core/java/android/annotation/CurrentTimeSecondsLong.java", - "core/java/android/annotation/DrawableRes.java", - "core/java/android/annotation/DurationMillisLong.java", - "core/java/android/annotation/Hide.java", - "core/java/android/annotation/IntDef.java", - "core/java/android/annotation/IntRange.java", - "core/java/android/annotation/LongDef.java", - "core/java/android/annotation/MainThread.java", - "core/java/android/annotation/NonNull.java", - "core/java/android/annotation/Nullable.java", - "core/java/android/annotation/RequiresPermission.java", - "core/java/android/annotation/SdkConstant.java", - "core/java/android/annotation/StringDef.java", - "core/java/android/annotation/SystemApi.java", - "core/java/android/annotation/SystemService.java", - "core/java/android/annotation/TestApi.java", - "core/java/android/annotation/UserIdInt.java", - "core/java/android/annotation/WorkerThread.java", - "core/java/com/android/internal/annotations/GuardedBy.java", - "core/java/com/android/internal/annotations/Immutable.java", - "core/java/com/android/internal/annotations/VisibleForTesting.java", - ], -} - -java_library { - name: "framework-annotations-lib", - srcs: [":framework-annotations"], - sdk_version: "core_current", -} - -filegroup { name: "framework-ike-shared-srcs", visibility: ["//packages/modules/IPsec"], srcs: [ @@ -473,8 +435,21 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x "--api-lint-ignore-prefix junit. " + "--api-lint-ignore-prefix org. " +packages_to_document = [ + "android", + "dalvik", + "java", + "javax", + "junit", + "org.apache.http", + "org.json", + "org.w3c.dom", + "org.xml.sax", + "org.xmlpull", +] + filegroup { - name: "framework-non-updatable-stub-sources", + name: "android-non-updatable-stub-sources", srcs: [ ":framework-mime-sources", // mimemap builds separately but has no separate droidstubs. ":framework-non-updatable-sources", @@ -486,6 +461,61 @@ filegroup { visibility: ["//visibility:private"], } +// These defaults are used for both the jar stubs and the doc stubs. +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: ["core/res/AndroidManifest.xml"], + // TODO(b/147699819): remove below aidl includes. + aidl: { + local_include_dirs: [ + "apex/media/aidl/stable", + // TODO: move to include-dirs for packages/modules/Connectivity when this moves out of + // frameworks/base + "packages/Connectivity/framework/aidl-export", + "telephony/java", + ], + }, + // 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.tv.tuner-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", + "art.module.public.api", + // 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", + ], + 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: ["//visibility:private"], + visibility: ["//frameworks/base/api"], +} + build = [ "StubLibraries.bp", "ApiDocs.bp", diff --git a/ApiDocs.bp b/ApiDocs.bp index d3bef7f9046b..83ace022950d 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -56,9 +56,23 @@ framework_docs_only_libs = [ ] stubs_defaults { + name: "android-non-updatable-doc-stubs-defaults", + defaults: ["android-non-updatable-stubs-defaults"], + srcs: [ + // No longer part of the stubs, but are included in the docs. + "test-base/src/**/*.java", + "test-mock/src/**/*.java", + "test-runner/src/**/*.java", + ], + libs: framework_docs_only_libs, + create_doc_stubs: true, + write_sdk_values: true, +} + +stubs_defaults { name: "framework-doc-stubs-default", srcs: [ - ":framework-non-updatable-stub-sources", + ":android-non-updatable-stub-sources", // Module sources ":art.module.public.api{.public.stubs.source}", @@ -75,13 +89,14 @@ stubs_defaults { ":updatable-media-srcs", // No longer part of the stubs, but are included in the docs. - "test-base/src/**/*.java", - "test-mock/src/**/*.java", - "test-runner/src/**/*.java", + ":android-test-base-sources", + ":android-test-mock-sources", + ":android-test-runner-sources", ], libs: framework_docs_only_libs, create_doc_stubs: true, annotations_enabled: true, + filter_packages: packages_to_document, api_levels_annotations_enabled: true, api_levels_annotations_dirs: [ "sdk-dir", @@ -94,14 +109,25 @@ stubs_defaults { } droidstubs { + name: "android-non-updatable-doc-stubs", + defaults: ["android-non-updatable-doc-stubs-defaults"], + args: metalava_framework_docs_args, +} + +droidstubs { + name: "android-non-updatable-doc-stubs-system", + defaults: ["android-non-updatable-doc-stubs-defaults"], + args: metalava_framework_docs_args + + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ", +} + +droidstubs { name: "framework-doc-stubs", defaults: ["framework-doc-stubs-default"], arg_files: [ "core/res/AndroidManifest.xml", ], - args: metalava_framework_docs_args + - // Needed for hidden libcore annotations for now. - " --ignore-classes-on-classpath ", + args: metalava_framework_docs_args, write_sdk_values: true, } @@ -112,8 +138,6 @@ droidstubs { "core/res/AndroidManifest.xml", ], args: metalava_framework_docs_args + - // Needed for hidden libcore annotations for now. - " --ignore-classes-on-classpath " + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ", write_sdk_values: true, } diff --git a/StubLibraries.bp b/StubLibraries.bp index 00d077192a01..626f9772655d 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -27,74 +27,11 @@ // Common metalava configs ///////////////////////////////////////////////////////////////////// -packages_to_document = [ - "android", - "dalvik", - "java", - "javax", - "junit", - "org.apache.http", - "org.json", - "org.w3c.dom", - "org.xml.sax", - "org.xmlpull", -] - stubs_defaults { name: "metalava-non-updatable-api-stubs-default", - srcs: [":framework-non-updatable-stub-sources"], - sdk_version: "none", - system_modules: "none", - java_version: "1.8", - arg_files: ["core/res/AndroidManifest.xml"], - // TODO(b/147699819): remove below aidl includes. - aidl: { - local_include_dirs: [ - "apex/media/aidl/stable", - // TODO: move to include-dirs for packages/modules/Connectivity when this moves out of - // frameworks/base - "packages/Connectivity/framework/aidl-export", - "telephony/java", - ], - }, - // 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.tv.tuner-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", - "stable.core.platform.api.stubs", - // 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", - ], - 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: ["android-non-updatable-stubs-defaults"], api_levels_annotations_enabled: false, - filter_packages: packages_to_document, defaults_visibility: ["//visibility:private"], - visibility: ["//frameworks/base/api"], } ///////////////////////////////////////////////////////////////////// @@ -347,7 +284,7 @@ java_defaults { visibility: ["//visibility:private"], } -java_library_static { +java_library { name: "android-non-updatable.stubs", defaults: ["android-non-updatable_defaults_stubs_current"], srcs: [":api-stubs-docs-non-updatable"], @@ -357,7 +294,7 @@ java_library_static { }, } -java_library_static { +java_library { name: "android-non-updatable.stubs.system", defaults: ["android-non-updatable_defaults_stubs_current"], srcs: [":system-api-stubs-docs-non-updatable"], @@ -367,7 +304,7 @@ java_library_static { }, } -java_library_static { +java_library { name: "android-non-updatable.stubs.module_lib", defaults: ["android-non-updatable_defaults_stubs_current"], srcs: [":module-lib-api-stubs-docs-non-updatable"], @@ -381,7 +318,7 @@ java_library_static { }, } -java_library_static { +java_library { name: "android-non-updatable.stubs.test", defaults: ["android-non-updatable_defaults_stubs_current"], srcs: [":test-api-stubs-docs-non-updatable"], @@ -404,7 +341,7 @@ java_defaults { defaults_visibility: ["//frameworks/base/services"], } -java_library_static { +java_library { name: "android_stubs_current", static_libs: modules_public_stubs + [ "android-non-updatable.stubs", @@ -413,7 +350,7 @@ java_library_static { defaults: ["android.jar_defaults"], } -java_library_static { +java_library { name: "android_system_stubs_current", static_libs: modules_system_stubs + [ "android-non-updatable.stubs.system", @@ -439,7 +376,7 @@ java_library_static { ], } -java_library_static { +java_library { name: "android_test_stubs_current", // Modules do not have test APIs, but we want to include their SystemApis, like we include // the SystemApi of framework-non-updatable-sources. @@ -456,7 +393,7 @@ java_library_static { }, } -java_library_static { +java_library { name: "android_module_lib_stubs_current", defaults: [ "android.jar_defaults", @@ -471,6 +408,22 @@ java_library_static { }, } +java_library { + name: "android_system_server_stubs_current", + defaults: ["android_stubs_dists_default"], + srcs: [":services-non-updatable-stubs"], + installable: false, + static_libs: [ + "android_module_lib_stubs_current", + ], + sdk_version: "none", + system_modules: "none", + java_version: "1.8", + dist: { + dir: "apistubs/android/system-server", + }, +} + ///////////////////////////////////////////////////////////////////// // hwbinder.stubs provides APIs required for building HIDL Java // libraries. @@ -504,7 +457,7 @@ droidstubs { visibility: ["//visibility:private"], } -java_library_static { +java_library { name: "hwbinder.stubs", sdk_version: "core_current", libs: ["framework-annotations-lib"], diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index 26010ef6d55c..bdab7d084a2a 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -545,7 +545,7 @@ public final class JobStore { out.attribute(null, "net-capabilities", Long.toString( BitUtils.packBits(network.getCapabilities()))); out.attribute(null, "net-unwanted-capabilities", Long.toString( - BitUtils.packBits(network.getUnwantedCapabilities()))); + BitUtils.packBits(network.getForbiddenCapabilities()))); out.attribute(null, "net-transport-types", Long.toString( BitUtils.packBits(network.getTransportTypes()))); @@ -968,22 +968,22 @@ public final class JobStore { String val; final String netCapabilities = parser.getAttributeValue(null, "net-capabilities"); - final String netUnwantedCapabilities = parser.getAttributeValue( + final String netforbiddenCapabilities = parser.getAttributeValue( null, "net-unwanted-capabilities"); final String netTransportTypes = parser.getAttributeValue(null, "net-transport-types"); if (netCapabilities != null && netTransportTypes != null) { final NetworkRequest.Builder builder = new NetworkRequest.Builder() .clearCapabilities(); - final long unwantedCapabilities = netUnwantedCapabilities != null - ? Long.parseLong(netUnwantedCapabilities) - : BitUtils.packBits(builder.build().getUnwantedCapabilities()); + final long forbiddenCapabilities = netforbiddenCapabilities != null + ? Long.parseLong(netforbiddenCapabilities) + : BitUtils.packBits(builder.build().getForbiddenCapabilities()); // We're okay throwing NFE here; caught by caller for (int capability : BitUtils.unpackBits(Long.parseLong(netCapabilities))) { builder.addCapability(capability); } - for (int unwantedCapability : BitUtils.unpackBits( - Long.parseLong(netUnwantedCapabilities))) { - builder.addUnwantedCapability(unwantedCapability); + for (int forbiddenCapability : BitUtils.unpackBits( + Long.parseLong(netforbiddenCapabilities))) { + builder.addForbiddenCapability(forbiddenCapability); } for (int transport : BitUtils.unpackBits(Long.parseLong(netTransportTypes))) { builder.addTransportType(transport); diff --git a/apex/media/Android.bp b/apex/media/Android.bp index 308741a6733d..a75f1aed4ade 100644 --- a/apex/media/Android.bp +++ b/apex/media/Android.bp @@ -24,3 +24,10 @@ package { // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["frameworks_base_license"], } + +sdk { + name: "media-module-sdk", + java_sdk_libs: [ + "framework-media", + ], +} diff --git a/api/Android.bp b/api/Android.bp index 6e83c083245a..5b2d97f11378 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -24,12 +24,17 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +metalava_cmd = "$(location metalava)" +// Silence reflection warnings. See b/168689341 +metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED " +metalava_cmd += " --no-banner --format=v2 " + genrule { name: "current-api-xml", tools: ["metalava"], srcs: [":frameworks-base-api-current.txt"], out: ["current.api"], - cmd: "$(location metalava) --no-banner -convert2xmlnostrip $(in) $(out)", + cmd: metalava_cmd + "-convert2xmlnostrip $(in) $(out)", visibility: ["//visibility:public"], } @@ -52,7 +57,7 @@ genrule { ], out: ["current.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + cmd: metalava_cmd + "$(in) --api $(out)", dists: [ { targets: ["droidcore"], @@ -77,7 +82,7 @@ genrule { ], out: ["stdout.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 " + + cmd: metalava_cmd + "--check-compatibility:api:released $(location :android.api.public.latest) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.public.latest) " + "$(location :frameworks-base-api-current.txt) " + @@ -126,7 +131,7 @@ genrule { ], out: ["removed.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + cmd: metalava_cmd + "$(in) --api $(out)", dists: [ { targets: ["droidcore"], @@ -157,7 +162,7 @@ genrule { ], out: ["system-current.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + cmd: metalava_cmd + "$(in) --api $(out)", dists: [ { targets: ["droidcore"], @@ -183,7 +188,7 @@ genrule { ], out: ["stdout.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 " + + cmd: metalava_cmd + "--check-compatibility:api:released $(location :android.api.system.latest) " + "--check-compatibility:base $(location :frameworks-base-api-current.txt) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.system.latest) " + @@ -207,7 +212,7 @@ genrule { ], out: ["system-removed.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + cmd: metalava_cmd + "$(in) --api $(out)", dists: [ { targets: ["droidcore"], @@ -239,7 +244,7 @@ genrule { ], out: ["module-lib-current.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + cmd: metalava_cmd + "$(in) --api $(out)", dists: [ { targets: ["droidcore"], @@ -264,7 +269,7 @@ genrule { ], out: ["stdout.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 " + + cmd: metalava_cmd + "--check-compatibility:api:released $(location :android.api.module-lib.latest) " + // Note: having "public" be the base of module-lib is not perfect -- it should // ideally be a merged public+system), but this will help when migrating from @@ -291,7 +296,7 @@ genrule { ], out: ["module-lib-removed.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + cmd: metalava_cmd + "$(in) --api $(out)", dists: [ { targets: ["droidcore"], @@ -331,7 +336,7 @@ genrule { ], out: ["system-server-current.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + cmd: metalava_cmd + "$(in) --api $(out)", dists: [ { targets: ["droidcore"], @@ -341,7 +346,7 @@ genrule { { targets: ["sdk", "win_sdk"], dir: "apistubs/android/system-server/api", - dest: "merge-android.txt", + dest: "android.txt", }, ], } @@ -354,7 +359,7 @@ genrule { ], out: ["system-server-removed.txt"], tools: ["metalava"], - cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + cmd: metalava_cmd + "$(in) --api $(out)", dists: [ { targets: ["droidcore"], @@ -364,7 +369,7 @@ genrule { { targets: ["sdk", "win_sdk"], dir: "apistubs/android/system-server/api", - dest: "merge-removed.txt", + dest: "removed.txt", }, ], } diff --git a/boot/Android.bp b/boot/Android.bp index ef2abc885fcf..3caede47d859 100644 --- a/boot/Android.bp +++ b/boot/Android.bp @@ -98,4 +98,12 @@ platform_bootclasspath { dest: "hiddenapi-unsupported.csv", }, ], + + required: [ + "platform-systemserverclasspath", + ], +} + +platform_systemserverclasspath { + name: "platform-systemserverclasspath", } diff --git a/boot/OWNERS b/boot/OWNERS index 0648888a9a1a..0e258d042c08 100644 --- a/boot/OWNERS +++ b/boot/OWNERS @@ -1,2 +1,6 @@ # soong-team@ as the platform_bootclasspath module is tightly coupled with Soong file:platform/build/soong:/OWNERS + +# art-team@ manages the boot image profiles for frameworks +per-file boot-* = calin@google.com, yawanng@google.com, ngeoffray@google.com +per-file preloaded-classes* = calin@google.com, yawanng@google.com, ngeoffray@google.com diff --git a/boot/boot-image-profile.txt b/boot/boot-image-profile.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/boot/boot-image-profile.txt diff --git a/boot/preloaded-classes b/boot/preloaded-classes new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/boot/preloaded-classes diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl index 403d8c55de16..a47b8416dbf5 100644 --- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl +++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl @@ -20,14 +20,16 @@ package android.os; * @see ResourcesTypes.h ResTable_overlayable_policy_header::PolicyFlags * @hide */ -interface OverlayablePolicy { - const int PUBLIC = 0x00000001; - const int SYSTEM_PARTITION = 0x00000002; - const int VENDOR_PARTITION = 0x00000004; - const int PRODUCT_PARTITION = 0x00000008; - const int SIGNATURE = 0x00000010; - const int ODM_PARTITION = 0x00000020; - const int OEM_PARTITION = 0x00000040; - const int ACTOR_SIGNATURE = 0x00000080; - const int CONFIG_SIGNATURE = 0x0000100; +@Backing(type="int") +enum OverlayablePolicy { + NONE = 0x00000000, + PUBLIC = 0x00000001, + SYSTEM_PARTITION = 0x00000002, + VENDOR_PARTITION = 0x00000004, + PRODUCT_PARTITION = 0x00000008, + SIGNATURE = 0x00000010, + ODM_PARTITION = 0x00000020, + OEM_PARTITION = 0x00000040, + ACTOR_SIGNATURE = 0x00000080, + CONFIG_SIGNATURE = 0x0000100, } diff --git a/core/api/current.txt b/core/api/current.txt index 0c637755bf5f..cd4e6f9a826c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -19377,15 +19377,23 @@ package android.media { field public static final int ENCODING_DEFAULT = 1; // 0x1 field public static final int ENCODING_DOLBY_MAT = 19; // 0x13 field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe + field public static final int ENCODING_DRA = 28; // 0x1c field public static final int ENCODING_DTS = 7; // 0x7 field public static final int ENCODING_DTS_HD = 8; // 0x8 + field public static final int ENCODING_DTS_UHD = 27; // 0x1b field public static final int ENCODING_E_AC3 = 6; // 0x6 field public static final int ENCODING_E_AC3_JOC = 18; // 0x12 field public static final int ENCODING_IEC61937 = 13; // 0xd field public static final int ENCODING_INVALID = 0; // 0x0 field public static final int ENCODING_MP3 = 9; // 0x9 + field public static final int ENCODING_MPEGH_BL_L3 = 23; // 0x17 + field public static final int ENCODING_MPEGH_BL_L4 = 24; // 0x18 + field public static final int ENCODING_MPEGH_LC_L3 = 25; // 0x19 + field public static final int ENCODING_MPEGH_LC_L4 = 26; // 0x1a field public static final int ENCODING_OPUS = 20; // 0x14 field public static final int ENCODING_PCM_16BIT = 2; // 0x2 + field public static final int ENCODING_PCM_24BIT_PACKED = 21; // 0x15 + field public static final int ENCODING_PCM_32BIT = 22; // 0x16 field public static final int ENCODING_PCM_8BIT = 3; // 0x3 field public static final int ENCODING_PCM_FLOAT = 4; // 0x4 field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0 @@ -21438,6 +21446,8 @@ package android.media { field public static final String MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw"; field public static final String MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw"; field public static final String MIMETYPE_AUDIO_MPEG = "audio/mpeg"; + field public static final String MIMETYPE_AUDIO_MPEGH_MHA1 = "audio/mha1"; + field public static final String MIMETYPE_AUDIO_MPEGH_MHM1 = "audio/mhm1"; field public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm"; field public static final String MIMETYPE_AUDIO_OPUS = "audio/opus"; field public static final String MIMETYPE_AUDIO_QCELP = "audio/qcelp"; @@ -25138,9 +25148,6 @@ package android.net { field public static final int UNSUPPORTED = -1; // 0xffffffff } - public interface TunnelConnectionParams { - } - public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable { method public abstract android.net.Uri.Builder buildUpon(); method public int compareTo(android.net.Uri); @@ -25705,16 +25712,16 @@ package android.net.vcn { method @NonNull public int[] getExposedCapabilities(); method @NonNull public String getGatewayConnectionName(); method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu(); - method @NonNull public long[] getRetryIntervalsMs(); + method @NonNull public long[] getRetryIntervalsMillis(); } public static final class VcnGatewayConnectionConfig.Builder { - ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.TunnelConnectionParams); + ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.ipsec.ike.IkeTunnelConnectionParams); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build(); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) int); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMs(@NonNull long[]); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMillis(@NonNull long[]); } public class VcnManager { @@ -31473,6 +31480,7 @@ package android.print { field public static final android.print.PrintAttributes.MediaSize JPN_HAGAKI; field public static final android.print.PrintAttributes.MediaSize JPN_KAHU; field public static final android.print.PrintAttributes.MediaSize JPN_KAKU2; + field @NonNull public static final android.print.PrintAttributes.MediaSize JPN_OE_PHOTO_L; field public static final android.print.PrintAttributes.MediaSize JPN_OUFUKU; field public static final android.print.PrintAttributes.MediaSize JPN_YOU4; field @NonNull public static final android.print.PrintAttributes.MediaSize NA_ARCH_A; @@ -31494,7 +31502,6 @@ package android.print { field public static final android.print.PrintAttributes.MediaSize NA_QUARTO; field @NonNull public static final android.print.PrintAttributes.MediaSize NA_SUPER_B; field public static final android.print.PrintAttributes.MediaSize NA_TABLOID; - field @NonNull public static final android.print.PrintAttributes.MediaSize OE_PHOTO_L; field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI; field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI; field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI; @@ -40401,7 +40408,6 @@ package android.telephony { method @IntRange(from=1, to=261) public int getBand(); method @IntRange(from=1) public int getCellBandwidthDownlinkKhz(); method @IntRange(from=1) public int getCellBandwidthUplinkKhz(); - method @Deprecated public int getChannelNumber(); method public int getConnectionStatus(); method @IntRange(from=0) public int getDownlinkChannelNumber(); method @IntRange(from=0) public int getDownlinkFrequencyKhz(); @@ -40790,6 +40796,8 @@ package android.telephony { method public static int getDefaultSmsSubscriptionId(); method public static int getDefaultSubscriptionId(); method public static int getDefaultVoiceSubscriptionId(); + method public int getDeviceToDeviceStatusSharing(int); + method @NonNull public java.util.List<android.net.Uri> getDeviceToDeviceStatusSharingContacts(int); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(); method public static int getSlotIndex(int); method @Nullable public int[] getSubscriptionIds(int); @@ -40802,6 +40810,8 @@ package android.telephony { method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharing(int, int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharingContacts(@NonNull java.util.List<android.net.Uri>, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int); method public void setSubscriptionOverrideCongested(int, boolean, long); method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long); @@ -40813,6 +40823,12 @@ package android.telephony { field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED"; field public static final String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS"; field public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS"; + field public static final int D2D_SHARING_ALL = 3; // 0x3 + field public static final int D2D_SHARING_ALL_CONTACTS = 1; // 0x1 + field public static final int D2D_SHARING_DISABLED = 0; // 0x0 + field public static final int D2D_SHARING_SELECTED_CONTACTS = 2; // 0x2 + field public static final String D2D_STATUS_SHARING = "d2d_sharing_status"; + field public static final String D2D_STATUS_SHARING_SELECTED_CONTACTS = "d2d_sharing_contacts"; field public static final int DATA_ROAMING_DISABLE = 0; // 0x0 field public static final int DATA_ROAMING_ENABLE = 1; // 0x1 field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 66ac74ac84d9..5d23eb20a81a 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -59,13 +59,13 @@ package android.net { public final class NetworkStateSnapshot implements android.os.Parcelable { ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int); method public int describeContents(); + method public int getLegacyType(); + method @NonNull public android.net.LinkProperties getLinkProperties(); + method @NonNull public android.net.Network getNetwork(); + method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); + method @Nullable public String getSubscriberId(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR; - field public final int legacyType; - field @NonNull public final android.net.LinkProperties linkProperties; - field @NonNull public final android.net.Network network; - field @NonNull public final android.net.NetworkCapabilities networkCapabilities; - field @Nullable public final String subscriberId; } public class NetworkWatchlistManager { @@ -89,11 +89,11 @@ package android.net { public final class UnderlyingNetworkInfo implements android.os.Parcelable { ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>); method public int describeContents(); + method @NonNull public String getInterface(); + method public int getOwnerUid(); + method @NonNull public java.util.List<java.lang.String> getUnderlyingInterfaces(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.UnderlyingNetworkInfo> CREATOR; - field @NonNull public final String iface; - field public final int ownerUid; - field @NonNull public final java.util.List<java.lang.String> underlyingIfaces; } public class VpnManager { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ef3a54387d25..bb42ddcda37f 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1124,10 +1124,11 @@ package android.app.backup { package android.app.compat { public final class CompatChanges { + method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void addPackageOverrides(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>); method public static boolean isChangeEnabled(long); method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int); - method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void setPackageOverride(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>); + method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void removePackageOverrides(@NonNull String, @NonNull java.util.Set<java.lang.Long>); } public final class PackageOverride { @@ -1503,7 +1504,7 @@ package android.bluetooth { public static interface BluetoothAdapter.OobDataCallback { method public void onError(int); - method public void onOobData(int, @Nullable android.bluetooth.OobData); + method public void onOobData(int, @NonNull android.bluetooth.OobData); } public final class BluetoothDevice implements android.os.Parcelable { @@ -1685,8 +1686,6 @@ package android.bluetooth { } public final class OobData implements android.os.Parcelable { - method @NonNull public static android.bluetooth.OobData.ClassicBuilder createClassicBuilder(@NonNull byte[], @NonNull byte[], @NonNull byte[]); - method @NonNull public static android.bluetooth.OobData.LeBuilder createLeBuilder(@NonNull byte[], @NonNull byte[], int); method @NonNull public byte[] getClassOfDevice(); method @NonNull public byte[] getClassicLength(); method @NonNull public byte[] getConfirmationHash(); @@ -1719,6 +1718,7 @@ package android.bluetooth { } public static final class OobData.ClassicBuilder { + ctor public OobData.ClassicBuilder(@NonNull byte[], @NonNull byte[], @NonNull byte[]); method @NonNull public android.bluetooth.OobData build(); method @NonNull public android.bluetooth.OobData.ClassicBuilder setClassOfDevice(@NonNull byte[]); method @NonNull public android.bluetooth.OobData.ClassicBuilder setDeviceName(@NonNull byte[]); @@ -1726,6 +1726,7 @@ package android.bluetooth { } public static final class OobData.LeBuilder { + ctor public OobData.LeBuilder(@NonNull byte[], @NonNull byte[], int); method @NonNull public android.bluetooth.OobData build(); method @NonNull public android.bluetooth.OobData.LeBuilder setDeviceName(@NonNull byte[]); method @NonNull public android.bluetooth.OobData.LeBuilder setLeFlags(int); @@ -10069,6 +10070,7 @@ package android.telephony { method public boolean canManageSubscription(@NonNull android.telephony.SubscriptionInfo, @NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getActiveSubscriptionIdList(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public byte[] getAllSimSpecificSettingsForBackup(); method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getCompleteActiveSubscriptionIdList(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int); @@ -10076,6 +10078,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int); method public void requestEmbeddedSubscriptionInfoListRefresh(); method public void requestEmbeddedSubscriptionInfoListRefresh(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void restoreAllSimSpecificSettingsFromBackup(@NonNull byte[]); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultDataSubId(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultSmsSubId(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultVoiceSubscriptionId(int); @@ -12328,6 +12331,7 @@ package android.telephony.ims.stub { field public static final int REGISTRATION_TECH_IWLAN = 1; // 0x1 field public static final int REGISTRATION_TECH_LTE = 0; // 0x0 field public static final int REGISTRATION_TECH_NONE = -1; // 0xffffffff + field public static final int REGISTRATION_TECH_NR = 3; // 0x3 } public class ImsSmsImplBase { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index fd6d47e56b52..3b759a2f69d0 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -14,6 +14,7 @@ package android { field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS"; field public static final String FORCE_DEVICE_POLICY_MANAGER_LOGS = "android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS"; field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; + field public static final String INSTALL_TEST_ONLY_PACKAGE = "android.permission.INSTALL_TEST_ONLY_PACKAGE"; field public static final String KEEP_UNINSTALLED_PACKAGES = "android.permission.KEEP_UNINSTALLED_PACKAGES"; field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES"; @@ -536,6 +537,10 @@ package android.content.pm { field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ProviderInfoList> CREATOR; } + public final class SharedLibraryInfo implements android.os.Parcelable { + method @NonNull public java.util.List<java.lang.String> getAllCodePaths(); + } + public final class ShortcutInfo implements android.os.Parcelable { method public boolean isVisibleToPublisher(); } @@ -1190,6 +1195,7 @@ package android.os { public class VintfObject { method public static String[] getHalNamesAndVersions(); + method @NonNull public static String getPlatformSepolicyVersion(); method public static String getSepolicyVersion(); method public static Long getTargetFrameworkCompatibilityMatrixVersion(); method public static java.util.Map<java.lang.String,java.lang.String[]> getVndkSnapshots(); @@ -1683,6 +1689,7 @@ package android.telephony { public class TelephonyManager { method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting); method public int getCarrierIdListVersion(); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCertsFromCarrierPrivilegeAccessRules(); method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); diff --git a/core/java/Android.bp b/core/java/Android.bp index 965665d3184a..874704e6350e 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -46,43 +46,6 @@ filegroup { "android/accounts/AccountsException.java", "android/accounts/AuthenticatorException.java", "android/accounts/OperationCanceledException.java", - "android/annotation/AnimatorRes.java", - "android/annotation/AnimRes.java", - "android/annotation/AnyRes.java", - "android/annotation/ArrayRes.java", - "android/annotation/AttrRes.java", - "android/annotation/BoolRes.java", - "android/annotation/BroadcastBehavior.java", - "android/annotation/CallbackExecutor.java", - "android/annotation/CallSuper.java", - "android/annotation/CheckResult.java", - "android/annotation/ColorInt.java", - "android/annotation/ColorRes.java", - "android/annotation/DimenRes.java", - "android/annotation/DrawableRes.java", - "android/annotation/FontRes.java", - "android/annotation/FractionRes.java", - "android/annotation/IntDef.java", - "android/annotation/IntegerRes.java", - "android/annotation/IntRange.java", - "android/annotation/LayoutRes.java", - "android/annotation/NonNull.java", - "android/annotation/Nullable.java", - "android/annotation/PluralsRes.java", - "android/annotation/RawRes.java", - "android/annotation/RequiresPermission.java", - "android/annotation/SdkConstant.java", - "android/annotation/Size.java", - "android/annotation/StringDef.java", - "android/annotation/StringRes.java", - "android/annotation/StyleableRes.java", - "android/annotation/StyleRes.java", - "android/annotation/SuppressLint.java", - "android/annotation/SystemApi.java", - "android/annotation/SystemService.java", - "android/annotation/TestApi.java", - "android/annotation/UserIdInt.java", - "android/annotation/XmlRes.java", "android/app/Application.java", "android/app/IApplicationThread.aidl", "android/app/IServiceConnection.aidl", @@ -123,7 +86,6 @@ filegroup { "android/util/AndroidException.java", "android/view/DisplayAdjustments.java", "android/view/ViewDebug.java", - "com/android/internal/annotations/VisibleForTesting.java", ], visibility: ["//frameworks/base/test-mock"], } diff --git a/core/java/android/annotation/AnimRes.java b/core/java/android/annotation/AnimRes.java deleted file mode 100644 index 56f8acf82313..000000000000 --- a/core/java/android/annotation/AnimRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an anim resource reference (e.g. {@link android.R.anim#fade_in}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AnimRes { -} diff --git a/core/java/android/annotation/AnimatorRes.java b/core/java/android/annotation/AnimatorRes.java deleted file mode 100644 index cd4c189b7531..000000000000 --- a/core/java/android/annotation/AnimatorRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an animator resource reference (e.g. {@link android.R.animator#fade_in}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AnimatorRes { -} diff --git a/core/java/android/annotation/AnyRes.java b/core/java/android/annotation/AnyRes.java deleted file mode 100644 index 44411a04a8e7..000000000000 --- a/core/java/android/annotation/AnyRes.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a resource reference of any type. If the specific type is known, use - * one of the more specific annotations instead, such as {@link StringRes} or - * {@link DrawableRes}. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AnyRes { -} diff --git a/core/java/android/annotation/AnyThread.java b/core/java/android/annotation/AnyThread.java deleted file mode 100644 index ee36a42b3fc6..000000000000 --- a/core/java/android/annotation/AnyThread.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated method can be called from any thread (e.g. it is - * "thread safe".) If the annotated element is a class, then all methods in the - * class can be called from any thread. - * <p> - * The main purpose of this method is to indicate that you believe a method can - * be called from any thread; static tools can then check that nothing you call - * from within this method or class have more strict threading requirements. - * <p> - * Example: - * - * <pre> - * <code> - * @AnyThread - * public void deliverResult(D data) { ... } - * </code> - * </pre> - * - * @memberDoc This method is safe to call from any thread. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface AnyThread { -} diff --git a/core/java/android/annotation/AppIdInt.java b/core/java/android/annotation/AppIdInt.java deleted file mode 100644 index 29838dd5bd7c..000000000000 --- a/core/java/android/annotation/AppIdInt.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element is a multi-user application ID. This is - * <em>not</em> the same as a UID. - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AppIdInt { -} diff --git a/core/java/android/annotation/ArrayRes.java b/core/java/android/annotation/ArrayRes.java deleted file mode 100644 index 1407af1d1422..000000000000 --- a/core/java/android/annotation/ArrayRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an array resource reference (e.g. {@link android.R.array#phoneTypes}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface ArrayRes { -} diff --git a/core/java/android/annotation/AttrRes.java b/core/java/android/annotation/AttrRes.java deleted file mode 100644 index 285b80ce45ca..000000000000 --- a/core/java/android/annotation/AttrRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an attribute reference (e.g. {@link android.R.attr#action}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AttrRes { -} diff --git a/core/java/android/annotation/BinderThread.java b/core/java/android/annotation/BinderThread.java deleted file mode 100644 index ca5e14c2adb9..000000000000 --- a/core/java/android/annotation/BinderThread.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated method should only be called on the binder thread. - * If the annotated element is a class, then all methods in the class should be called - * on the binder thread. - * <p> - * Example: - * <pre><code> - * @BinderThread - * public BeamShareData createBeamShareData() { ... } - * </code></pre> - * - * {@hide} - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface BinderThread { -}
\ No newline at end of file diff --git a/core/java/android/annotation/BoolRes.java b/core/java/android/annotation/BoolRes.java deleted file mode 100644 index f50785b1e1cf..000000000000 --- a/core/java/android/annotation/BoolRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a boolean resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface BoolRes { -} diff --git a/core/java/android/annotation/BroadcastBehavior.java b/core/java/android/annotation/BroadcastBehavior.java deleted file mode 100644 index 70d82cb5151b..000000000000 --- a/core/java/android/annotation/BroadcastBehavior.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import android.content.Intent; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Description of how the annotated broadcast action behaves. - * - * @hide - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.SOURCE) -public @interface BroadcastBehavior { - /** - * This broadcast will only be delivered to an explicit target. - * - * @see Intent#setPackage(String) - * @see Intent#setComponent(android.content.ComponentName) - */ - boolean explicitOnly() default false; - - /** - * This broadcast will only be delivered to registered receivers. - * - * @see Intent#FLAG_RECEIVER_REGISTERED_ONLY - */ - boolean registeredOnly() default false; - - /** - * This broadcast will include all {@code AndroidManifest.xml} receivers - * regardless of process state. - * - * @see Intent#FLAG_RECEIVER_INCLUDE_BACKGROUND - */ - boolean includeBackground() default false; - - /** - * This broadcast is protected and can only be sent by the OS. - */ - boolean protectedBroadcast() default false; -} diff --git a/core/java/android/annotation/BytesLong.java b/core/java/android/annotation/BytesLong.java deleted file mode 100644 index f5e1a9c5f7fd..000000000000 --- a/core/java/android/annotation/BytesLong.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative number of bytes. - * @paramDoc Value is a non-negative number of bytes. - * @returnDoc Value is a non-negative number of bytes. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface BytesLong { -} diff --git a/core/java/android/annotation/CallSuper.java b/core/java/android/annotation/CallSuper.java deleted file mode 100644 index c16b51161cac..000000000000 --- a/core/java/android/annotation/CallSuper.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that any overriding methods should invoke this method as well. - * <p> - * Example: - * - * <pre> - * <code> - * @CallSuper - * public abstract void onFocusLost(); - * </code> - * </pre> - * - * @memberDoc If you override this method you <em>must</em> call through to the - * superclass implementation. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD}) -public @interface CallSuper { -} diff --git a/core/java/android/annotation/CallbackExecutor.java b/core/java/android/annotation/CallbackExecutor.java deleted file mode 100644 index 4258f730eb16..000000000000 --- a/core/java/android/annotation/CallbackExecutor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.util.concurrent.Executor; - -/** - * @paramDoc Callback and listener events are dispatched through this - * {@link Executor}, providing an easy way to control which thread is - * used. To dispatch events through the main thread of your - * application, you can use - * {@link android.content.Context#getMainExecutor() Context.getMainExecutor()}. - * To dispatch events through a shared thread pool, you can use - * {@link android.os.AsyncTask#THREAD_POOL_EXECUTOR AsyncTask#THREAD_POOL_EXECUTOR}. - * @hide - */ -@Retention(SOURCE) -@Target(PARAMETER) -public @interface CallbackExecutor { -} diff --git a/core/java/android/annotation/CheckResult.java b/core/java/android/annotation/CheckResult.java deleted file mode 100644 index 97d031a760a6..000000000000 --- a/core/java/android/annotation/CheckResult.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated method returns a result that it typically is - * an error to ignore. This is usually used for methods that have no side effect, - * so calling it without actually looking at the result usually means the developer - * has misunderstood what the method does. - * <p> - * Example: - * <pre>{@code - * public @CheckResult String trim(String s) { return s.trim(); } - * ... - * s.trim(); // this is probably an error - * s = s.trim(); // ok - * }</pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD}) -public @interface CheckResult { - /** Defines the name of the suggested method to use instead, if applicable (using - * the same signature format as javadoc.) If there is more than one possibility, - * list them all separated by commas. - * <p> - * For example, ProcessBuilder has a method named {@code redirectErrorStream()} - * which sounds like it might redirect the error stream. It does not. It's just - * a getter which returns whether the process builder will redirect the error stream, - * and to actually set it, you must call {@code redirectErrorStream(boolean)}. - * In that case, the method should be defined like this: - * <pre> - * @CheckResult(suggest="#redirectErrorStream(boolean)") - * public boolean redirectErrorStream() { ... } - * </pre> - */ - String suggest() default ""; -}
\ No newline at end of file diff --git a/core/java/android/annotation/ColorInt.java b/core/java/android/annotation/ColorInt.java deleted file mode 100644 index 4671b1b9f887..000000000000 --- a/core/java/android/annotation/ColorInt.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element represents a packed color - * int, {@code AARRGGBB}. If applied to an int array, every element - * in the array represents a color integer. - * <p> - * Example: - * <pre>{@code - * public abstract void setTextColor(@ColorInt int color); - * }</pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD}) -public @interface ColorInt { -}
\ No newline at end of file diff --git a/core/java/android/annotation/ColorLong.java b/core/java/android/annotation/ColorLong.java deleted file mode 100644 index 9b19c76802c9..000000000000 --- a/core/java/android/annotation/ColorLong.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * <p>Denotes that the annotated element represents a packed color - * long. If applied to a long array, every element in the array - * represents a color long. For more information on how colors - * are packed in a long, please refer to the documentation of - * the {@link android.graphics.Color} class.</p> - * - * <p>Example:</p> - * - * <pre>{@code - * public void setFillColor(@ColorLong long color); - * }</pre> - * - * @see android.graphics.Color - * - * @hide - */ -@Retention(SOURCE) -@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD}) -public @interface ColorLong { -} diff --git a/core/java/android/annotation/ColorRes.java b/core/java/android/annotation/ColorRes.java deleted file mode 100644 index 061faa05c738..000000000000 --- a/core/java/android/annotation/ColorRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a color resource reference (e.g. {@link android.R.color#black}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface ColorRes { -} diff --git a/core/java/android/annotation/Condemned.java b/core/java/android/annotation/Condemned.java deleted file mode 100644 index 186409b3e204..000000000000 --- a/core/java/android/annotation/Condemned.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * A program element annotated @Condemned is one that programmers are - * blocked from using, typically because it's about to be completely destroyed. - * <p> - * This is a stronger version of @Deprecated, and it's typically used to - * mark APIs that only existed temporarily in a preview SDK, and which only - * continue to exist temporarily to support binary compatibility. - * - * @hide - */ -@Retention(SOURCE) -@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) -public @interface Condemned { -} diff --git a/core/java/android/annotation/CurrentTimeMillisLong.java b/core/java/android/annotation/CurrentTimeMillisLong.java deleted file mode 100644 index 355bb5a2f960..000000000000 --- a/core/java/android/annotation/CurrentTimeMillisLong.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative timestamp measured as the number of - * milliseconds since 1970-01-01T00:00:00Z. - * @paramDoc Value is a non-negative timestamp measured as the number of - * milliseconds since 1970-01-01T00:00:00Z. - * @returnDoc Value is a non-negative timestamp measured as the number of - * milliseconds since 1970-01-01T00:00:00Z. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface CurrentTimeMillisLong { -} diff --git a/core/java/android/annotation/CurrentTimeSecondsLong.java b/core/java/android/annotation/CurrentTimeSecondsLong.java deleted file mode 100644 index 2b4ffd77ad34..000000000000 --- a/core/java/android/annotation/CurrentTimeSecondsLong.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative timestamp measured as the number of - * seconds since 1970-01-01T00:00:00Z. - * @paramDoc Value is a non-negative timestamp measured as the number of - * seconds since 1970-01-01T00:00:00Z. - * @returnDoc Value is a non-negative timestamp measured as the number of - * seconds since 1970-01-01T00:00:00Z. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface CurrentTimeSecondsLong { -} diff --git a/core/java/android/annotation/DimenRes.java b/core/java/android/annotation/DimenRes.java deleted file mode 100644 index 02ae00c6868c..000000000000 --- a/core/java/android/annotation/DimenRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a dimension resource reference (e.g. {@link android.R.dimen#app_icon_size}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface DimenRes { -} diff --git a/core/java/android/annotation/Dimension.java b/core/java/android/annotation/Dimension.java deleted file mode 100644 index 5f705ad52d9b..000000000000 --- a/core/java/android/annotation/Dimension.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that a numeric parameter, field or method return value is expected - * to represent a dimension. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE}) -public @interface Dimension { - @Unit - int unit() default PX; - - int DP = 0; - int PX = 1; - int SP = 2; - - @IntDef({PX, DP, SP}) - @Retention(SOURCE) - @interface Unit {} -} diff --git a/core/java/android/annotation/DrawableRes.java b/core/java/android/annotation/DrawableRes.java deleted file mode 100644 index ebefa1d78ab1..000000000000 --- a/core/java/android/annotation/DrawableRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a drawable resource reference (e.g. {@link android.R.attr#alertDialogIcon}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface DrawableRes { -} diff --git a/core/java/android/annotation/DurationMillisLong.java b/core/java/android/annotation/DurationMillisLong.java deleted file mode 100644 index ce77532a6c6e..000000000000 --- a/core/java/android/annotation/DurationMillisLong.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative duration in milliseconds. - * @paramDoc Value is a non-negative duration in milliseconds. - * @returnDoc Value is a non-negative duration in milliseconds. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface DurationMillisLong { -} diff --git a/core/java/android/annotation/ElapsedRealtimeLong.java b/core/java/android/annotation/ElapsedRealtimeLong.java deleted file mode 100644 index f77ff72062a6..000000000000 --- a/core/java/android/annotation/ElapsedRealtimeLong.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.os.SystemClock; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative timestamp in the - * {@link SystemClock#elapsedRealtime()} time base. - * @paramDoc Value is a non-negative timestamp in the - * {@link SystemClock#elapsedRealtime()} time base. - * @returnDoc Value is a non-negative timestamp in the - * {@link SystemClock#elapsedRealtime()} time base. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface ElapsedRealtimeLong { -} diff --git a/core/java/android/annotation/FloatRange.java b/core/java/android/annotation/FloatRange.java deleted file mode 100644 index 05b51680b1b0..000000000000 --- a/core/java/android/annotation/FloatRange.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element should be a float or double in the given range - * <p> - * Example: - * <pre><code> - * @FloatRange(from=0.0,to=1.0) - * public float getAlpha() { - * ... - * } - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE}) -public @interface FloatRange { - /** Smallest value. Whether it is inclusive or not is determined - * by {@link #fromInclusive} */ - double from() default Double.NEGATIVE_INFINITY; - /** Largest value. Whether it is inclusive or not is determined - * by {@link #toInclusive} */ - double to() default Double.POSITIVE_INFINITY; - - /** Whether the from value is included in the range */ - boolean fromInclusive() default true; - - /** Whether the to value is included in the range */ - boolean toInclusive() default true; -}
\ No newline at end of file diff --git a/core/java/android/annotation/FontRes.java b/core/java/android/annotation/FontRes.java deleted file mode 100644 index dbacb5876dce..000000000000 --- a/core/java/android/annotation/FontRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a Font resource reference (e.g. R.font.myfont). - * - * @hide - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface FontRes { -} diff --git a/core/java/android/annotation/FractionRes.java b/core/java/android/annotation/FractionRes.java deleted file mode 100644 index fd84d3e85fdf..000000000000 --- a/core/java/android/annotation/FractionRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a fraction resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface FractionRes { -} diff --git a/core/java/android/annotation/HalfFloat.java b/core/java/android/annotation/HalfFloat.java deleted file mode 100644 index 256008c5e31f..000000000000 --- a/core/java/android/annotation/HalfFloat.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * <p>Denotes that the annotated element represents a half-precision floating point - * value. Such values are stored in short data types and can be manipulated with - * the {@link android.util.Half} class. If applied to an array of short, every - * element in the array represents a half-precision float.</p> - * - * <p>Example:</p> - * - * <pre>{@code - * public abstract void setPosition(@HalfFloat short x, @HalfFloat short y, @HalfFloat short z); - * }</pre> - * - * @see android.util.Half - * @see android.util.Half#toHalf(float) - * @see android.util.Half#toFloat(short) - * - * @hide - */ -@Retention(SOURCE) -@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD}) -public @interface HalfFloat { -} diff --git a/core/java/android/annotation/Hide.java b/core/java/android/annotation/Hide.java deleted file mode 100644 index c8e5a4a97ae7..000000000000 --- a/core/java/android/annotation/Hide.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates that an API is hidden by default, in a similar fashion to the - * <pre>@hide</pre> javadoc tag. - * - * <p>Note that, in order for this to work, metalava has to be invoked with - * the flag {@code --hide-annotation android.annotation.Hide}. - * @hide - */ -@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) -@Retention(RetentionPolicy.CLASS) -public @interface Hide { -} diff --git a/core/java/android/annotation/IdRes.java b/core/java/android/annotation/IdRes.java deleted file mode 100644 index b286965c99d9..000000000000 --- a/core/java/android/annotation/IdRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an id resource reference (e.g. {@link android.R.id#copy}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface IdRes { -} diff --git a/core/java/android/annotation/IntDef.java b/core/java/android/annotation/IntDef.java deleted file mode 100644 index f84a67655dc3..000000000000 --- a/core/java/android/annotation/IntDef.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element of integer type, represents - * a logical type and that its value should be one of the explicitly - * named constants. If the {@link #flag()} attribute is set to true, - * multiple constants can be combined. - * <p> - * <pre><code> - * @Retention(SOURCE) - * @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) - * public @interface NavigationMode {} - * public static final int NAVIGATION_MODE_STANDARD = 0; - * public static final int NAVIGATION_MODE_LIST = 1; - * public static final int NAVIGATION_MODE_TABS = 2; - * ... - * public abstract void setNavigationMode(@NavigationMode int mode); - * @NavigationMode - * public abstract int getNavigationMode(); - * </code></pre> - * For a flag, set the flag attribute: - * <pre><code> - * @IntDef( - * flag = true, - * value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({ANNOTATION_TYPE}) -public @interface IntDef { - /** Defines the constant prefix for this element */ - String[] prefix() default {}; - /** Defines the constant suffix for this element */ - String[] suffix() default {}; - - /** Defines the allowed constants for this element */ - int[] value() default {}; - - /** Defines whether the constants can be used as a flag, or just as an enum (the default) */ - boolean flag() default false; -} diff --git a/core/java/android/annotation/IntRange.java b/core/java/android/annotation/IntRange.java deleted file mode 100644 index c043e2db6a98..000000000000 --- a/core/java/android/annotation/IntRange.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element should be an int or long in the given range - * <p> - * Example: - * <pre><code> - * @IntRange(from=0,to=255) - * public int getAlpha() { - * ... - * } - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE}) -public @interface IntRange { - /** Smallest value, inclusive */ - long from() default Long.MIN_VALUE; - /** Largest value, inclusive */ - long to() default Long.MAX_VALUE; -}
\ No newline at end of file diff --git a/core/java/android/annotation/IntegerRes.java b/core/java/android/annotation/IntegerRes.java deleted file mode 100644 index 5313f4adf46e..000000000000 --- a/core/java/android/annotation/IntegerRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an integer resource reference (e.g. {@link android.R.integer#config_shortAnimTime}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface IntegerRes { -} diff --git a/core/java/android/annotation/InterpolatorRes.java b/core/java/android/annotation/InterpolatorRes.java deleted file mode 100644 index 8877a5f9a4f1..000000000000 --- a/core/java/android/annotation/InterpolatorRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an interpolator resource reference (e.g. {@link android.R.interpolator#cycle}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface InterpolatorRes { -} diff --git a/core/java/android/annotation/LayoutRes.java b/core/java/android/annotation/LayoutRes.java deleted file mode 100644 index 15ba86f98159..000000000000 --- a/core/java/android/annotation/LayoutRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a layout resource reference (e.g. {@link android.R.layout#list_content}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface LayoutRes { -} diff --git a/core/java/android/annotation/LongDef.java b/core/java/android/annotation/LongDef.java deleted file mode 100644 index 8723eef86328..000000000000 --- a/core/java/android/annotation/LongDef.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated long element represents - * a logical type and that its value should be one of the explicitly - * named constants. If the {@link #flag()} attribute is set to true, - * multiple constants can be combined. - * <p> - * <pre><code> - * @Retention(SOURCE) - * @LongDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) - * public @interface NavigationMode {} - * public static final long NAVIGATION_MODE_STANDARD = 0; - * public static final long NAVIGATION_MODE_LIST = 1; - * public static final long NAVIGATION_MODE_TABS = 2; - * ... - * public abstract void setNavigationMode(@NavigationMode long mode); - * @NavigationMode - * public abstract long getNavigationMode(); - * </code></pre> - * For a flag, set the flag attribute: - * <pre><code> - * @LongDef( - * flag = true, - * value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({ANNOTATION_TYPE}) -public @interface LongDef { - /** Defines the constant prefix for this element */ - String[] prefix() default ""; - - /** Defines the allowed constants for this element */ - long[] value() default {}; - - /** Defines whether the constants can be used as a flag, or just as an enum (the default) */ - boolean flag() default false; -} diff --git a/core/java/android/annotation/MainThread.java b/core/java/android/annotation/MainThread.java deleted file mode 100644 index a070246e5ef3..000000000000 --- a/core/java/android/annotation/MainThread.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated method should only be called on the main thread. - * If the annotated element is a class, then all methods in the class should be - * called on the main thread. - * <p> - * Example: - * - * <pre> - * <code> - * @MainThread - * public void deliverResult(D data) { ... } - * </code> - * </pre> - * - * @memberDoc This method must be called from the main thread of your app. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface MainThread { -} diff --git a/core/java/android/annotation/MenuRes.java b/core/java/android/annotation/MenuRes.java deleted file mode 100644 index b6dcc4604cfb..000000000000 --- a/core/java/android/annotation/MenuRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a menu resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface MenuRes { -} diff --git a/core/java/android/annotation/NavigationRes.java b/core/java/android/annotation/NavigationRes.java deleted file mode 100644 index 3af5ecff84a6..000000000000 --- a/core/java/android/annotation/NavigationRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a navigation resource reference (e.g. {@code R.navigation.flow}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface NavigationRes { -} diff --git a/core/java/android/annotation/NonNull.java b/core/java/android/annotation/NonNull.java deleted file mode 100644 index 20472bacf6ad..000000000000 --- a/core/java/android/annotation/NonNull.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that a parameter, field or method return value can never be null. - * <p> - * This is a marker annotation and it has no specific attributes. - * - * @paramDoc This value cannot be {@code null}. - * @returnDoc This value cannot be {@code null}. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface NonNull { -} diff --git a/core/java/android/annotation/Nullable.java b/core/java/android/annotation/Nullable.java deleted file mode 100644 index b8473e750c95..000000000000 --- a/core/java/android/annotation/Nullable.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that a parameter, field or method return value can be null. - * <p> - * When decorating a method call parameter, this denotes that the parameter can - * legitimately be null and the method will gracefully deal with it. Typically - * used on optional parameters. - * <p> - * When decorating a method, this denotes the method might legitimately return - * null. - * <p> - * This is a marker annotation and it has no specific attributes. - * - * @paramDoc This value may be {@code null}. - * @returnDoc This value may be {@code null}. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface Nullable { -} diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS deleted file mode 100644 index e1ef54460b56..000000000000 --- a/core/java/android/annotation/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -tnorbye@google.com -aurimas@google.com -per-file UnsupportedAppUsage.java = mathewi@google.com, satayev@google.com, andreionea@google.com diff --git a/core/java/android/annotation/PluralsRes.java b/core/java/android/annotation/PluralsRes.java deleted file mode 100644 index 31ac729aaa47..000000000000 --- a/core/java/android/annotation/PluralsRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a plurals resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface PluralsRes { -} diff --git a/core/java/android/annotation/Px.java b/core/java/android/annotation/Px.java deleted file mode 100644 index cec7f80405d3..000000000000 --- a/core/java/android/annotation/Px.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that a numeric parameter, field or method return value is expected - * to represent a pixel dimension. - * - * @memberDoc This units of this value are pixels. - * @paramDoc This units of this value are pixels. - * @returnDoc This units of this value are pixels. - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE}) -@Dimension(unit = Dimension.PX) -public @interface Px { -} diff --git a/core/java/android/annotation/RawRes.java b/core/java/android/annotation/RawRes.java deleted file mode 100644 index 39970b36fd95..000000000000 --- a/core/java/android/annotation/RawRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a raw resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface RawRes { -} diff --git a/core/java/android/annotation/RequiresFeature.java b/core/java/android/annotation/RequiresFeature.java deleted file mode 100644 index 08861d42be39..000000000000 --- a/core/java/android/annotation/RequiresFeature.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.content.pm.PackageManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element requires one or more device features. This - * is used to auto-generate documentation. - * - * @hide - */ -@Retention(SOURCE) -@Target({TYPE,FIELD,METHOD,CONSTRUCTOR}) -public @interface RequiresFeature { - /** - * The name of the device feature that is required. - */ - String value(); - - /** - * Defines the name of the method that should be called to check whether the feature is - * available, using the same signature format as javadoc. The feature checking method can have - * multiple parameters, but the feature name parameter must be of type String and must also be - * the first String-type parameter. - * <p> - * By default, the enforcement is {@link PackageManager#hasSystemFeature(String)}. - */ - String enforcement() default("android.content.pm.PackageManager#hasSystemFeature"); -} diff --git a/core/java/android/annotation/RequiresPermission.java b/core/java/android/annotation/RequiresPermission.java deleted file mode 100644 index 1d89e31b2b99..000000000000 --- a/core/java/android/annotation/RequiresPermission.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element requires (or may require) one or more permissions. - * <p/> - * Example of requiring a single permission: - * <pre>{@code - * {@literal @}RequiresPermission(Manifest.permission.SET_WALLPAPER) - * public abstract void setWallpaper(Bitmap bitmap) throws IOException; - * - * {@literal @}RequiresPermission(ACCESS_COARSE_LOCATION) - * public abstract Location getLastKnownLocation(String provider); - * }</pre> - * Example of requiring at least one permission from a set: - * <pre>{@code - * {@literal @}RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - * public abstract Location getLastKnownLocation(String provider); - * }</pre> - * Example of requiring multiple permissions: - * <pre>{@code - * {@literal @}RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - * public abstract Location getLastKnownLocation(String provider); - * }</pre> - * Example of requiring separate read and write permissions for a content provider: - * <pre>{@code - * {@literal @}RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS)) - * {@literal @}RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS)) - * public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks"); - * }</pre> - * <p> - * When specified on a parameter, the annotation indicates that the method requires - * a permission which depends on the value of the parameter. For example, consider - * {@link android.app.Activity#startActivity(android.content.Intent) - * Activity#startActivity(Intent)}: - * <pre>{@code - * public void startActivity(@RequiresPermission Intent intent) { ... } - * }</pre> - * Notice how there are no actual permission names listed in the annotation. The actual - * permissions required will depend on the particular intent passed in. For example, - * the code may look like this: - * <pre>{@code - * Intent intent = new Intent(Intent.ACTION_CALL); - * startActivity(intent); - * }</pre> - * and the actual permission requirement for this particular intent is described on - * the Intent name itself: - * <pre>{@code - * {@literal @}RequiresPermission(Manifest.permission.CALL_PHONE) - * public static final String ACTION_CALL = "android.intent.action.CALL"; - * }</pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER}) -public @interface RequiresPermission { - /** - * The name of the permission that is required, if precisely one permission - * is required. If more than one permission is required, specify either - * {@link #allOf()} or {@link #anyOf()} instead. - * <p> - * If specified, {@link #anyOf()} and {@link #allOf()} must both be null. - */ - String value() default ""; - - /** - * Specifies a list of permission names that are all required. - * <p> - * If specified, {@link #anyOf()} and {@link #value()} must both be null. - */ - String[] allOf() default {}; - - /** - * Specifies a list of permission names where at least one is required - * <p> - * If specified, {@link #allOf()} and {@link #value()} must both be null. - */ - String[] anyOf() default {}; - - /** - * If true, the permission may not be required in all cases (e.g. it may only be - * enforced on certain platforms, or for certain call parameters, etc. - */ - boolean conditional() default false; - - /** - * Specifies that the given permission is required for read operations. - * <p> - * When specified on a parameter, the annotation indicates that the method requires - * a permission which depends on the value of the parameter (and typically - * the corresponding field passed in will be one of a set of constants which have - * been annotated with a <code>@RequiresPermission</code> annotation.) - */ - @Target({FIELD, METHOD, PARAMETER}) - @interface Read { - RequiresPermission value() default @RequiresPermission; - } - - /** - * Specifies that the given permission is required for write operations. - * <p> - * When specified on a parameter, the annotation indicates that the method requires - * a permission which depends on the value of the parameter (and typically - * the corresponding field passed in will be one of a set of constants which have - * been annotated with a <code>@RequiresPermission</code> annotation.) - */ - @Target({FIELD, METHOD, PARAMETER}) - @interface Write { - RequiresPermission value() default @RequiresPermission; - } -} diff --git a/core/java/android/annotation/SdkConstant.java b/core/java/android/annotation/SdkConstant.java deleted file mode 100644 index 0a5318609847..000000000000 --- a/core/java/android/annotation/SdkConstant.java +++ /dev/null @@ -1,36 +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.annotation; - -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Indicates a constant field value should be exported to be used in the SDK tools. - * @hide - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.SOURCE) -public @interface SdkConstant { - public static enum SdkConstantType { - ACTIVITY_INTENT_ACTION, BROADCAST_INTENT_ACTION, SERVICE_ACTION, INTENT_CATEGORY, FEATURE; - } - - SdkConstantType value(); -} diff --git a/core/java/android/annotation/Size.java b/core/java/android/annotation/Size.java deleted file mode 100644 index 7c3e70f658e9..000000000000 --- a/core/java/android/annotation/Size.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element should have a given size or length. - * Note that "-1" means "unset". Typically used with a parameter or - * return value of type array or collection. - * <p> - * Example: - * <pre>{@code - * public void getLocationInWindow(@Size(2) int[] location) { - * ... - * } - * }</pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD}) -public @interface Size { - /** An exact size (or -1 if not specified) */ - long value() default -1; - /** A minimum size, inclusive */ - long min() default Long.MIN_VALUE; - /** A maximum size, inclusive */ - long max() default Long.MAX_VALUE; - /** The size must be a multiple of this factor */ - long multiple() default 1; -}
\ No newline at end of file diff --git a/core/java/android/annotation/StringDef.java b/core/java/android/annotation/StringDef.java deleted file mode 100644 index a37535b9c98e..000000000000 --- a/core/java/android/annotation/StringDef.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated String element, represents a logical - * type and that its value should be one of the explicitly named constants. - * <p> - * Example: - * <pre><code> - * @Retention(SOURCE) - * @StringDef({ - * POWER_SERVICE, - * WINDOW_SERVICE, - * LAYOUT_INFLATER_SERVICE - * }) - * public @interface ServiceName {} - * public static final String POWER_SERVICE = "power"; - * public static final String WINDOW_SERVICE = "window"; - * public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater"; - * ... - * public abstract Object getSystemService(@ServiceName String name); - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({ANNOTATION_TYPE}) -public @interface StringDef { - /** Defines the constant prefix for this element */ - String[] prefix() default {}; - /** Defines the constant suffix for this element */ - String[] suffix() default {}; - - /** Defines the allowed constants for this element */ - String[] value() default {}; -} diff --git a/core/java/android/annotation/StringRes.java b/core/java/android/annotation/StringRes.java deleted file mode 100644 index 190b68a9960b..000000000000 --- a/core/java/android/annotation/StringRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a String resource reference (e.g. {@link android.R.string#ok}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface StringRes { -} diff --git a/core/java/android/annotation/StyleRes.java b/core/java/android/annotation/StyleRes.java deleted file mode 100644 index 4453b8d89153..000000000000 --- a/core/java/android/annotation/StyleRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that a integer parameter, field or method return value is expected - * to be a style resource reference (e.g. {@link android.R.style#TextAppearance}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface StyleRes { -} diff --git a/core/java/android/annotation/StyleableRes.java b/core/java/android/annotation/StyleableRes.java deleted file mode 100644 index 3c1895e6dce9..000000000000 --- a/core/java/android/annotation/StyleableRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that a integer parameter, field or method return value is expected - * to be a styleable resource reference (e.g. {@link android.R.styleable#TextView_text}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface StyleableRes { -} diff --git a/core/java/android/annotation/SuppressAutoDoc.java b/core/java/android/annotation/SuppressAutoDoc.java deleted file mode 100644 index e34e03bcee29..000000000000 --- a/core/java/android/annotation/SuppressAutoDoc.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that any automatically generated documentation should be suppressed - * for the annotated method, parameter, or field. - * - * @hide - */ -@Retention(SOURCE) -@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) -public @interface SuppressAutoDoc { -} diff --git a/core/java/android/annotation/SuppressLint.java b/core/java/android/annotation/SuppressLint.java deleted file mode 100644 index 2d3456b0ea46..000000000000 --- a/core/java/android/annotation/SuppressLint.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Indicates that Lint should ignore the specified warnings for the annotated element. */ -@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) -@Retention(RetentionPolicy.CLASS) -public @interface SuppressLint { - /** - * The set of warnings (identified by the lint issue id) that should be - * ignored by lint. It is not an error to specify an unrecognized name. - */ - String[] value(); -} diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java deleted file mode 100644 index a468439c8e74..000000000000 --- a/core/java/android/annotation/SystemApi.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates an API is exposed for use by bundled system applications. - * <p> - * These APIs are not guaranteed to remain consistent release-to-release, - * and are not for use by apps linking against the Android SDK. - * </p><p> - * This annotation should only appear on API that is already marked <pre>@hide</pre>. - * </p> - * - * @hide - */ -@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface SystemApi { - enum Client { - /** - * Specifies that the intended clients of a SystemApi are privileged apps. - * This is the default value for {@link #client}. - */ - PRIVILEGED_APPS, - - /** - * Specifies that the intended clients of a SystemApi are used by classes in - * <pre>BOOTCLASSPATH</pre> in mainline modules. Mainline modules can also expose - * this type of system APIs too when they're used only by the non-updatable - * platform code. - */ - MODULE_LIBRARIES, - - /** - * Specifies that the system API is available only in the system server process. - * Use this to expose APIs from code loaded by the system server process <em>but</em> - * not in <pre>BOOTCLASSPATH</pre>. - */ - SYSTEM_SERVER - } - - /** - * The intended client of this SystemAPI. - */ - Client client() default android.annotation.SystemApi.Client.PRIVILEGED_APPS; - - /** - * Container for {@link SystemApi} that allows it to be applied repeatedly to types. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(TYPE) - @interface Container { - SystemApi[] value(); - } -} diff --git a/core/java/android/annotation/SystemService.java b/core/java/android/annotation/SystemService.java deleted file mode 100644 index c05c1bab06d2..000000000000 --- a/core/java/android/annotation/SystemService.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Description of a system service available through - * {@link android.content.Context#getSystemService(Class)}. This is used to auto-generate - * documentation explaining how to obtain a reference to the service. - * - * @hide - */ -@Retention(SOURCE) -@Target(TYPE) -public @interface SystemService { - /** - * The string name of the system service that can be passed to - * {@link android.content.Context#getSystemService(String)}. - * - * @see android.content.Context#getSystemServiceName(Class) - */ - String value(); -} diff --git a/core/java/android/annotation/TargetApi.java b/core/java/android/annotation/TargetApi.java deleted file mode 100644 index 975318e4de67..000000000000 --- a/core/java/android/annotation/TargetApi.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Indicates that Lint should treat this type as targeting a given API level, no matter what the - project target is. */ -@Target({TYPE, METHOD, CONSTRUCTOR, FIELD}) -@Retention(RetentionPolicy.CLASS) -public @interface TargetApi { - /** - * This sets the target api level for the type.. - */ - int value(); -} diff --git a/core/java/android/annotation/TestApi.java b/core/java/android/annotation/TestApi.java deleted file mode 100644 index 0e9ed3751246..000000000000 --- a/core/java/android/annotation/TestApi.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates an API is exposed for use by CTS. - * <p> - * These APIs are not guaranteed to remain consistent release-to-release, - * and are not for use by apps linking against the Android SDK. - * </p> - * - * @hide - */ -@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) -@Retention(RetentionPolicy.SOURCE) -public @interface TestApi { -} diff --git a/core/java/android/annotation/TransitionRes.java b/core/java/android/annotation/TransitionRes.java deleted file mode 100644 index 06bac74984a5..000000000000 --- a/core/java/android/annotation/TransitionRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a transition resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface TransitionRes { -} diff --git a/core/java/android/annotation/UiThread.java b/core/java/android/annotation/UiThread.java deleted file mode 100644 index 6d7eedc7d2e2..000000000000 --- a/core/java/android/annotation/UiThread.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.os.Looper; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated method or constructor should only be called on the - * UI thread. If the annotated element is a class, then all methods in the class - * should be called on the UI thread. - * <p> - * Example: - * - * <pre> - * <code> - * @UiThread - * public abstract void setText(@NonNull String text) { ... } - * </code> - * </pre> - * - * @memberDoc This method must be called on the thread that originally created - * this UI element. This is typically the - * {@linkplain Looper#getMainLooper() main thread} of your app. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface UiThread { -} diff --git a/core/java/android/annotation/UserHandleAware.java b/core/java/android/annotation/UserHandleAware.java deleted file mode 100644 index 7d3d20b31b2a..000000000000 --- a/core/java/android/annotation/UserHandleAware.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Indicates an API that uses {@code context.getUser} or {@code context.getUserId} - * to operate across users (as the user associated with the context) - * <p> - * To create a {@link android.content.Context} associated with a different user, - * use {@link android.content.Context#createContextAsUser} or - * {@link android.content.Context#createPackageContextAsUser} - * <p> - * Example: - * <pre>{@code - * {@literal @}UserHandleAware - * public abstract PackageInfo getPackageInfo({@literal @}NonNull String packageName, - * {@literal @}PackageInfoFlags int flags) throws NameNotFoundException; - * }</pre> - * - * @memberDoc This method uses {@linkplain android.content.Context#getUser} - * or {@linkplain android.content.Context#getUserId} to execute across users. - * @hide - */ -@Retention(SOURCE) -@Target({TYPE, METHOD, CONSTRUCTOR, PACKAGE}) -public @interface UserHandleAware { -} diff --git a/core/java/android/annotation/UserIdInt.java b/core/java/android/annotation/UserIdInt.java deleted file mode 100644 index 7b9ce25e3f1a..000000000000 --- a/core/java/android/annotation/UserIdInt.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element is a multi-user user ID. This is - * <em>not</em> the same as a UID. - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface UserIdInt { -} diff --git a/core/java/android/annotation/Widget.java b/core/java/android/annotation/Widget.java deleted file mode 100644 index 6756cd73c5fe..000000000000 --- a/core/java/android/annotation/Widget.java +++ /dev/null @@ -1,37 +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.annotation; - -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Indicates a class is a widget usable by application developers to create UI. - * <p> - * This must be used in cases where: - * <ul> - * <li>The widget is not in the package <code>android.widget</code></li> - * <li>The widget extends <code>android.view.ViewGroup</code></li> - * </ul> - * @hide - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.SOURCE) -public @interface Widget { -} diff --git a/core/java/android/annotation/WorkerThread.java b/core/java/android/annotation/WorkerThread.java deleted file mode 100644 index 8c2a4d381ab1..000000000000 --- a/core/java/android/annotation/WorkerThread.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated method should only be called on a worker thread. - * If the annotated element is a class, then all methods in the class should be - * called on a worker thread. - * <p> - * Example: - * - * <pre> - * <code> - * @WorkerThread - * protected abstract FilterResults performFiltering(CharSequence constraint); - * </code> - * </pre> - * - * @memberDoc This method may take several seconds to complete, so it should - * only be called from a worker thread. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface WorkerThread { -} diff --git a/core/java/android/annotation/XmlRes.java b/core/java/android/annotation/XmlRes.java deleted file mode 100644 index 5fb8a4a47127..000000000000 --- a/core/java/android/annotation/XmlRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an XML resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface XmlRes { -} diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java index 28a21f767283..134cef5b6bfa 100644 --- a/core/java/android/app/AppCompatCallbacks.java +++ b/core/java/android/app/AppCompatCallbacks.java @@ -28,7 +28,7 @@ import java.util.Arrays; * * @hide */ -public final class AppCompatCallbacks extends Compatibility.Callbacks { +public final class AppCompatCallbacks implements Compatibility.BehaviorChangeDelegate { private final long[] mDisabledChanges; private final ChangeReporter mChangeReporter; @@ -38,7 +38,7 @@ public final class AppCompatCallbacks extends Compatibility.Callbacks { * @param disabledChanges Set of compatibility changes that are disabled for this process. */ public static void install(long[] disabledChanges) { - Compatibility.setCallbacks(new AppCompatCallbacks(disabledChanges)); + Compatibility.setBehaviorChangeDelegate(new AppCompatCallbacks(disabledChanges)); } private AppCompatCallbacks(long[] disabledChanges) { @@ -48,11 +48,11 @@ public final class AppCompatCallbacks extends Compatibility.Callbacks { ChangeReporter.SOURCE_APP_PROCESS); } - protected void reportChange(long changeId) { + public void onChangeReported(long changeId) { reportChange(changeId, ChangeReporter.STATE_LOGGED); } - protected boolean isChangeEnabled(long changeId) { + public boolean isChangeEnabled(long changeId) { if (Arrays.binarySearch(mDisabledChanges, changeId) < 0) { // Not present in the disabled array reportChange(changeId, ChangeReporter.STATE_ENABLED); diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS index 8462cbe7497b..6acbef29bec3 100644 --- a/core/java/android/app/admin/OWNERS +++ b/core/java/android/app/admin/OWNERS @@ -3,9 +3,9 @@ # Android Enterprise team rubinxu@google.com sandness@google.com -eranm@google.com alexkershaw@google.com pgrafov@google.com # Emeritus yamasani@google.com +eranm@google.com diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java index 74e1ece3fa89..8ca43c4a8e70 100644 --- a/core/java/android/app/compat/CompatChanges.java +++ b/core/java/android/app/compat/CompatChanges.java @@ -26,9 +26,11 @@ import android.os.ServiceManager; import android.os.UserHandle; import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; import com.android.internal.compat.IPlatformCompat; import java.util.Map; +import java.util.Set; /** * CompatChanges APIs - to be used by platform code only (including mainline @@ -98,15 +100,19 @@ public final class CompatChanges { } /** - * Set an app compat override for a given package. This will check whether the caller is allowed + * Adds app compat overrides for a given package. This will check whether the caller is allowed * to perform this operation on the given apk and build. Only the installer package is allowed * to set overrides on a non-debuggable final build and a non-test apk. * + * <p>Note that calling this method doesn't remove previously added overrides for the given + * package if their change ID isn't in the given map, only replaces those that have the same + * change ID. + * * @param packageName The package name of the app in question. - * @param overrides A map from changeId to the override applied for this change id. + * @param overrides A map from change ID to the override applied for this change ID. */ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) - public static void setPackageOverride(@NonNull String packageName, + public static void addPackageOverrides(@NonNull String packageName, @NonNull Map<Long, PackageOverride> overrides) { IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); @@ -117,4 +123,29 @@ public final class CompatChanges { e.rethrowFromSystemServer(); } } + + /** + * Removes app compat overrides for a given package. This will check whether the caller is + * allowed to perform this operation on the given apk and build. Only the installer package is + * allowed to clear overrides on a non-debuggable final build and a non-test apk. + * + * <p>Note that calling this method with an empty set is a no-op and no overrides will be + * removed for the given package. + * + * @param packageName The package name of the app in question. + * @param overridesToRemove A set of change IDs for which to remove overrides. + */ + @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) + public static void removePackageOverrides(@NonNull String packageName, + @NonNull Set<Long> overridesToRemove) { + IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig( + overridesToRemove); + try { + platformCompat.removeOverridesOnReleaseBuilds(config, packageName); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java index 59b355523a30..fad6cd311021 100644 --- a/core/java/android/app/compat/PackageOverride.java +++ b/core/java/android/app/compat/PackageOverride.java @@ -19,6 +19,7 @@ package android.app.compat; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.content.pm.PackageInfo; import android.os.Parcel; import java.lang.annotation.Retention; @@ -101,12 +102,20 @@ public final class PackageOverride { return VALUE_UNDEFINED; } - /** Returns the minimum version code the override applies to. */ + /** + * Returns the minimum APK version code the override applies to. + * + * @see PackageInfo#getLongVersionCode() + */ public long getMinVersionCode() { return mMinVersionCode; } - /** Returns the minimum version code the override applies from. */ + /** + * Returns the maximum APK version code the override applies from. + * + * @see PackageInfo#getLongVersionCode() + */ public long getMaxVersionCode() { return mMaxVersionCode; } @@ -146,9 +155,11 @@ public final class PackageOverride { private boolean mEnabled; /** - * Sets the minimum version code the override should apply from. + * Sets the minimum APK version code the override should apply from. * * default value: {@code Long.MIN_VALUE}. + * + * @see PackageInfo#getLongVersionCode() */ @NonNull public Builder setMinVersionCode(long minVersionCode) { @@ -157,9 +168,11 @@ public final class PackageOverride { } /** - * Sets the maximum version code the override should apply to. + * Sets the maximum APK version code the override should apply to. * * default value: {@code Long.MAX_VALUE}. + * + * @see PackageInfo#getLongVersionCode() */ @NonNull public Builder setMaxVersionCode(long maxVersionCode) { diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 9f1132b605ef..6cb4b5e9b3d4 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -655,14 +655,14 @@ public class NetworkStatsManager { } /** - * Notify {@code NetworkStatsService} about network status changed. + * Notify {@code NetworkStatsService} about network status changed. * - * Notifies NetworkStatsService of network state changes for data usage accounting purposes. + * Notifies NetworkStatsService of network state changes for data usage accounting purposes. * - * To avoid races that attribute data usage to wrong network, such as new network with - * the same interface after SIM hot-swap, this function will not return until - * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from - * all data sources. + * To avoid races that attribute data usage to wrong network, such as new network with + * the same interface after SIM hot-swap, this function will not return until + * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from + * all data sources. * * @param defaultNetworks the list of all networks that could be used by network traffic that * does not explicitly select a network. @@ -689,8 +689,7 @@ public class NetworkStatsManager { Objects.requireNonNull(defaultNetworks); Objects.requireNonNull(networkStateSnapshots); Objects.requireNonNull(underlyingNetworkInfos); - // TODO: Change internal namings after the name is decided. - mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]), + mService.notifyNetworkStatus(defaultNetworks.toArray(new Network[0]), networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface, underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0])); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 3802289dd6d6..63221c5d8941 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -3063,7 +3063,7 @@ public final class BluetoothAdapter { * @param transport - whether the {@link OobData} is generated for LE or Classic. * @param oobData - data generated in the host stack(LE) or controller (Classic) */ - void onOobData(@Transport int transport, @Nullable OobData oobData); + void onOobData(@Transport int transport, @NonNull OobData oobData); /** * Provides feedback when things don't go as expected. @@ -3104,7 +3104,7 @@ public final class BluetoothAdapter { * * @hide */ - public void onOobData(@Transport int transport, OobData oobData) { + public void onOobData(@Transport int transport, @NonNull OobData oobData) { mExecutor.execute(new Runnable() { public void run() { mCallback.onOobData(transport, oobData); diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index a40bf343239e..11b45e32c425 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1605,13 +1605,13 @@ public final class BluetoothDevice implements Parcelable { * * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, * with the UUIDs supported by the remote end. If there is an error - * in getting the SDP records or if the process takes a long time, - * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently - * present in the cache. Clients should use the {@link #getUuids} to get UUIDs + * in getting the SDP records or if the process takes a long time, or the device is bonding and + * we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the UUIDs that is + * currently present in the cache. Clients should use the {@link #getUuids} to get UUIDs * if service discovery is not to be performed. * * @return False if the check fails, True if the process of initiating an ACL connection - * to the remote device was started. + * to the remote device was started or cached UUIDs will be broadcast. */ @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp() { diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java index d6868e0ffd5c..2dfa91dcba3e 100644 --- a/core/java/android/bluetooth/OobData.java +++ b/core/java/android/bluetooth/OobData.java @@ -25,7 +25,6 @@ import android.os.Parcelable; import com.android.internal.util.Preconditions; -import java.lang.IllegalArgumentException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -165,68 +164,6 @@ public final class OobData implements Parcelable { public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04; /** - * Main creation method for creating a Classic version of {@link OobData}. - * - * <p>This object will allow the caller to call {@link ClassicBuilder#build()} - * to build the data object or add any option information to the builder. - * - * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} octets - * of data. Data is derived from controller/host stack and is required for pairing OOB. - * @param classicLength byte array representing the length of data from 8-65535 across 2 - * octets (0xXXXX). - * @param deviceAddressWithType byte array representing the Bluetooth Address of the device - * that owns the OOB data. (i.e. the originator) [6 octets] - * - * @return a Classic Builder instance with all the given data set or null. - * - * @throws IllegalArgumentException if any of the values fail to be set. - * @throws NullPointerException if any argument is null. - * - * @hide - */ - @NonNull - @SystemApi - public static ClassicBuilder createClassicBuilder(@NonNull byte[] confirmationHash, - @NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType) { - return new ClassicBuilder(confirmationHash, classicLength, deviceAddressWithType); - } - - /** - * Main creation method for creating a LE version of {@link OobData}. - * - * <p>This object will allow the caller to call {@link LeBuilder#build()} - * to build the data object or add any option information to the builder. - * - * @param deviceAddressWithType the LE device address plus the address type (7 octets); - * not null. - * @param leDeviceRole whether the device supports Peripheral, Central, - * Both including preference; not null. (1 octet) - * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets - * of data. Data is derived from controller/host stack and is - * required for pairing OOB. - * - * <p>Possible LE Device Role Values: - * 0x00 Only Peripheral supported - * 0x01 Only Central supported - * 0x02 Central & Peripheral supported; Peripheral Preferred - * 0x03 Only peripheral supported; Central Preferred - * 0x04 - 0xFF Reserved - * - * @return a LeBuilder instance with all the given data set or null. - * - * @throws IllegalArgumentException if any of the values fail to be set. - * @throws NullPointerException if any argument is null. - * - * @hide - */ - @NonNull - @SystemApi - public static LeBuilder createLeBuilder(@NonNull byte[] confirmationHash, - @NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole) { - return new LeBuilder(confirmationHash, deviceAddressWithType, leDeviceRole); - } - - /** * Builds an {@link OobData} object and validates that the required combination * of values are present to create the LE specific OobData type. * @@ -342,16 +279,18 @@ public final class OobData implements Parcelable { private @LeFlag int mLeFlags = LE_FLAG_GENERAL_DISCOVERY_MODE; // Invalid default /** - * Constructing an OobData object for use with LE requires - * a LE Device Address and LE Device Role as well as the Confirmation - * and optionally, the Randomizer, however it is recommended to use. + * Main creation method for creating a LE version of {@link OobData}. * - * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} - * octets of data. Data is derived from controller/host stack and is required for - * pairing OOB. - * @param deviceAddressWithType 7 bytes containing the 6 byte address with the 1 byte - * address type. - * @param leDeviceRole indicating device's role and preferences (Central or Peripheral) + * <p>This object will allow the caller to call {@link LeBuilder#build()} + * to build the data object or add any option information to the builder. + * + * @param deviceAddressWithType the LE device address plus the address type (7 octets); + * not null. + * @param leDeviceRole whether the device supports Peripheral, Central, + * Both including preference; not null. (1 octet) + * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets + * of data. Data is derived from controller/host stack and is + * required for pairing OOB. * * <p>Possible Values: * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported @@ -361,11 +300,13 @@ public final class OobData implements Parcelable { * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred * 0x04 - 0xFF Reserved * - * @throws IllegalArgumentException if deviceAddressWithType is not - * {@link LE_DEVICE_ADDRESS_OCTETS} octets + * @throws IllegalArgumentException if any of the values fail to be set. * @throws NullPointerException if any argument is null. + * + * @hide */ - private LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType, + @SystemApi + public LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole) { Preconditions.checkNotNull(confirmationHash); Preconditions.checkNotNull(deviceAddressWithType); @@ -572,25 +513,26 @@ public final class OobData implements Parcelable { private byte[] mClassOfDevice = null; /** + * Main creation method for creating a Classic version of {@link OobData}. + * + * <p>This object will allow the caller to call {@link ClassicBuilder#build()} + * to build the data object or add any option information to the builder. + * * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} * octets of data. Data is derived from controller/host stack and is required for pairing * OOB. - * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets - * of data. Data is derived from controller/host stack and is required - * for pairing OOB. Also, randomizerHash may be all 0s or null in which case - * it becomes all 0s. * @param classicLength byte array representing the length of data from 8-65535 across 2 - * octets (0xXXXX). Inclusive of this value in the length. + * octets (0xXXXX). * @param deviceAddressWithType byte array representing the Bluetooth Address of the device - * that owns the OOB data. (i.e. the originator) [7 octets] this includes the Address Type - * as the last octet. + * that owns the OOB data. (i.e. the originator) [6 octets] * - * @throws IllegalArgumentException if any value is not the correct length - * @throws NullPointerException if anything passed is null + * @throws IllegalArgumentException if any of the values fail to be set. + * @throws NullPointerException if any argument is null. * * @hide */ - private ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength, + @SystemApi + public ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType) { Preconditions.checkNotNull(confirmationHash); Preconditions.checkNotNull(classicLength); diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index 3c20dcac8ca3..a74c663a9ce7 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -587,6 +587,10 @@ public final class ScanFilter implements Parcelable { * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. */ public Builder setDeviceAddress(String deviceAddress) { + if (deviceAddress == null) { + mDeviceAddress = deviceAddress; + return this; + } return setDeviceAddress(deviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC); } diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS index f0def80505ce..4e674f6ec9a8 100644 --- a/core/java/android/content/pm/OWNERS +++ b/core/java/android/content/pm/OWNERS @@ -4,7 +4,8 @@ toddke@android.com toddke@google.com patb@google.com -per-file PackageParser.java = chiuwinson@google.com +per-file PackageParser.java = set noparent +per-file PackageParser.java = chiuwinson@google.com,patb@google.com,toddke@google.com per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index da2a3d885fc6..933a0c9ba341 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -29,6 +30,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; /** * This class provides information for a shared library. There are @@ -177,7 +179,8 @@ public final class SharedLibraryInfo implements Parcelable { * * @hide */ - public List<String> getAllCodePaths() { + @TestApi + public @NonNull List<String> getAllCodePaths() { if (getPath() != null) { // Builtin library. ArrayList<String> list = new ArrayList<>(); @@ -185,7 +188,7 @@ public final class SharedLibraryInfo implements Parcelable { return list; } else { // Static or dynamic library. - return mCodePaths; + return Objects.requireNonNull(mCodePaths); } } diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html index 4d6ba28962d2..6ececa2e1416 100644 --- a/core/java/android/database/sqlite/package.html +++ b/core/java/android/database/sqlite/package.html @@ -20,6 +20,9 @@ with adb shell, for example, <code>adb -e shell sqlite3</code>. <p>The version of SQLite depends on the version of Android. See the following table: <table style="width:auto;"> <tr><th>Android API</th><th>SQLite Version</th></tr> + <tr><td>API 31</td><td>3.32</td></tr> + <tr><td>API 30</td><td>3.28</td></tr> + <tr><td>API 28</td><td>3.22</td></tr> <tr><td>API 27</td><td>3.19</td></tr> <tr><td>API 26</td><td>3.18</td></tr> <tr><td>API 24</td><td>3.9</td></tr> diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index e385cd2b7ecd..362a205d6178 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -26,6 +26,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; +import android.os.UserHandle; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.util.Slog; @@ -334,11 +335,23 @@ public class BiometricManager { * in Keystore land as SIDs, and are used during key generation. * @hide */ - @RequiresPermission(USE_BIOMETRIC_INTERNAL) public long[] getAuthenticatorIds() { + return getAuthenticatorIds(UserHandle.myUserId()); + } + + /** + * Get a list of AuthenticatorIDs for biometric authenticators which have 1) enrolled templates, + * and 2) meet the requirements for integrating with Keystore. The AuthenticatorIDs are known + * in Keystore land as SIDs, and are used during key generation. + * + * @param userId Android user ID for user to look up. + * + * @hide + */ + public long[] getAuthenticatorIds(int userId) { if (mService != null) { try { - return mService.getAuthenticatorIds(); + return mService.getAuthenticatorIds(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -347,6 +360,5 @@ public class BiometricManager { return new long[0]; } } - } diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl index a6f6c1ea0293..3542482927cb 100644 --- a/core/java/android/hardware/biometrics/IAuthService.aidl +++ b/core/java/android/hardware/biometrics/IAuthService.aidl @@ -55,5 +55,7 @@ interface IAuthService { // Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet // the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore // land as SIDs, and are used during key generation. - long[] getAuthenticatorIds(); + // If userId is not equal to the calling user ID, the caller must have the + // USE_BIOMETRIC_INTERNAL permission. + long[] getAuthenticatorIds(in int userId); } diff --git a/core/java/android/hardware/face/OWNERS b/core/java/android/hardware/face/OWNERS index be10df1099ed..0b4d9d9d6f54 100644 --- a/core/java/android/hardware/face/OWNERS +++ b/core/java/android/hardware/face/OWNERS @@ -1,7 +1,3 @@ # Bug component: 879035 -curtislb@google.com -ilyamaty@google.com -jaggies@google.com -joshmccloskey@google.com -kchyn@google.com +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/core/java/android/hardware/fingerprint/OWNERS b/core/java/android/hardware/fingerprint/OWNERS index e55b8c564ddb..5c9367240b8d 100644 --- a/core/java/android/hardware/fingerprint/OWNERS +++ b/core/java/android/hardware/fingerprint/OWNERS @@ -1,8 +1,3 @@ # Bug component: 114777 -curtislb@google.com -ilyamaty@google.com -jaggies@google.com -joshmccloskey@google.com -kchyn@google.com - +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/core/java/android/hardware/hdmi/OWNERS b/core/java/android/hardware/hdmi/OWNERS index 16c15e387bab..60d43fd077d0 100644 --- a/core/java/android/hardware/hdmi/OWNERS +++ b/core/java/android/hardware/hdmi/OWNERS @@ -4,3 +4,4 @@ include /services/core/java/com/android/server/display/OWNERS marvinramin@google.com nchalko@google.com +lcnathalie@google.com diff --git a/core/java/android/hardware/iris/OWNERS b/core/java/android/hardware/iris/OWNERS index 33527f824827..0b4d9d9d6f54 100644 --- a/core/java/android/hardware/iris/OWNERS +++ b/core/java/android/hardware/iris/OWNERS @@ -1,3 +1,3 @@ # Bug component: 879035 -jaggies@google.com +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index dc3b88a7c3be..12937b5cb2c7 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -65,8 +65,8 @@ interface INetworkStatsService { /** Increment data layer count of operations performed for UID and tag. */ void incrementOperationCount(int uid, int tag, int operationCount); - /** Force update of ifaces. */ - void forceUpdateIfaces( + /** Notify {@code NetworkStatsService} about network status changed. */ + void notifyNetworkStatus( in Network[] defaultNetworks, in NetworkStateSnapshot[] snapshots, in String activeIface, diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 98acd98cc465..01d1aa533a8f 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -79,6 +79,16 @@ public final class IpSecManager { public static final int DIRECTION_OUT = 1; /** + * Used when applying a transform to direct traffic through an {@link IpSecTransform} for + * forwarding between interfaces. + * + * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. + * + * @hide + */ + public static final int DIRECTION_FWD = 2; + + /** * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. * * <p>No IPsec packet may contain an SPI of 0. diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1eef7d9a5337..3bde6fa6913d 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -186,19 +186,19 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { */ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) { - final int legacyType = snapshot.legacyType; + final int legacyType = snapshot.getLegacyType(); - final String subscriberId = snapshot.subscriberId; + final String subscriberId = snapshot.getSubscriberId(); String networkId = null; - boolean roaming = !snapshot.networkCapabilities.hasCapability( + boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !snapshot.networkCapabilities.hasCapability( + boolean metered = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - final int oemManaged = getOemBitfield(snapshot.networkCapabilities); + final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); if (legacyType == TYPE_WIFI) { - networkId = snapshot.networkCapabilities.getSsid(); + networkId = snapshot.getNetworkCapabilities().getSsid(); if (networkId == null) { final WifiManager wifi = context.getSystemService(WifiManager.class); final WifiInfo info = wifi.getConnectionInfo(); diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java index 0d26c2de8698..9df861a6ffdc 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -37,47 +37,76 @@ import java.util.Objects; public final class NetworkStateSnapshot implements Parcelable { /** The network associated with this snapshot. */ @NonNull - public final Network network; + private final Network mNetwork; /** The {@link NetworkCapabilities} of the network associated with this snapshot. */ @NonNull - public final NetworkCapabilities networkCapabilities; + private final NetworkCapabilities mNetworkCapabilities; /** The {@link LinkProperties} of the network associated with this snapshot. */ @NonNull - public final LinkProperties linkProperties; + private final LinkProperties mLinkProperties; /** * The Subscriber Id of the network associated with this snapshot. See * {@link android.telephony.TelephonyManager#getSubscriberId()}. */ @Nullable - public final String subscriberId; + private final String mSubscriberId; /** * The legacy type of the network associated with this snapshot. See * {@code ConnectivityManager#TYPE_*}. */ - public final int legacyType; + private final int mLegacyType; public NetworkStateSnapshot(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, @Nullable String subscriberId, int legacyType) { - this.network = Objects.requireNonNull(network); - this.networkCapabilities = Objects.requireNonNull(networkCapabilities); - this.linkProperties = Objects.requireNonNull(linkProperties); - this.subscriberId = subscriberId; - this.legacyType = legacyType; + mNetwork = Objects.requireNonNull(network); + mNetworkCapabilities = Objects.requireNonNull(networkCapabilities); + mLinkProperties = Objects.requireNonNull(linkProperties); + mSubscriberId = subscriberId; + mLegacyType = legacyType; } /** @hide */ public NetworkStateSnapshot(@NonNull Parcel in) { - network = in.readParcelable(null); - networkCapabilities = in.readParcelable(null); - linkProperties = in.readParcelable(null); - subscriberId = in.readString(); - legacyType = in.readInt(); + mNetwork = in.readParcelable(null); + mNetworkCapabilities = in.readParcelable(null); + mLinkProperties = in.readParcelable(null); + mSubscriberId = in.readString(); + mLegacyType = in.readInt(); + } + + /** Get the network associated with this snapshot */ + @NonNull + public Network getNetwork() { + return mNetwork; + } + + /** Get {@link NetworkCapabilities} of the network associated with this snapshot. */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + /** Get the {@link LinkProperties} of the network associated with this snapshot. */ + @NonNull + public LinkProperties getLinkProperties() { + return mLinkProperties; + } + + /** Get the Subscriber Id of the network associated with this snapshot. */ + @Nullable + public String getSubscriberId() { + return mSubscriberId; + } + + /** Get the legacy type of the network associated with this snapshot. */ + public int getLegacyType() { + return mLegacyType; } @Override @@ -87,11 +116,11 @@ public final class NetworkStateSnapshot implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(network, flags); - out.writeParcelable(networkCapabilities, flags); - out.writeParcelable(linkProperties, flags); - out.writeString(subscriberId); - out.writeInt(legacyType); + out.writeParcelable(mNetwork, flags); + out.writeParcelable(mNetworkCapabilities, flags); + out.writeParcelable(mLinkProperties, flags); + out.writeString(mSubscriberId); + out.writeInt(mLegacyType); } @NonNull @@ -115,26 +144,27 @@ public final class NetworkStateSnapshot implements Parcelable { if (this == o) return true; if (!(o instanceof NetworkStateSnapshot)) return false; NetworkStateSnapshot that = (NetworkStateSnapshot) o; - return legacyType == that.legacyType - && Objects.equals(network, that.network) - && Objects.equals(networkCapabilities, that.networkCapabilities) - && Objects.equals(linkProperties, that.linkProperties) - && Objects.equals(subscriberId, that.subscriberId); + return mLegacyType == that.mLegacyType + && Objects.equals(mNetwork, that.mNetwork) + && Objects.equals(mNetworkCapabilities, that.mNetworkCapabilities) + && Objects.equals(mLinkProperties, that.mLinkProperties) + && Objects.equals(mSubscriberId, that.mSubscriberId); } @Override public int hashCode() { - return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType); + return Objects.hash(mNetwork, + mNetworkCapabilities, mLinkProperties, mSubscriberId, mLegacyType); } @Override public String toString() { return "NetworkStateSnapshot{" - + "network=" + network - + ", networkCapabilities=" + networkCapabilities - + ", linkProperties=" + linkProperties - + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + '\'' - + ", legacyType=" + legacyType + + "network=" + mNetwork + + ", networkCapabilities=" + mNetworkCapabilities + + ", linkProperties=" + mLinkProperties + + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId) + '\'' + + ", legacyType=" + mLegacyType + '}'; } } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index d42beae601ed..6ccbab7ed8ef 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -38,6 +38,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Predicate; @@ -1423,11 +1424,11 @@ public final class NetworkStats implements Parcelable { * @hide */ public void migrateTun(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces) { + @NonNull List<String> underlyingIfaces) { // Combined usage by all apps using VPN. final Entry tunIfaceTotal = new Entry(); // Usage by VPN, grouped by its {@code underlyingIfaces}. - final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; + final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.size()]; // Usage by VPN, summed across all its {@code underlyingIfaces}. final Entry underlyingIfacesTotal = new Entry(); @@ -1468,7 +1469,7 @@ public final class NetworkStats implements Parcelable { * {@code underlyingIfaces} */ private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull List<String> underlyingIfaces, @NonNull Entry tunIfaceTotal, @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { final Entry recycle = new Entry(); for (int i = 0; i < size; i++) { @@ -1488,8 +1489,8 @@ public final class NetworkStats implements Parcelable { if (recycle.uid == tunUid) { // Add up traffic through tunUid's underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - if (Objects.equals(underlyingIfaces[j], recycle.iface)) { + for (int j = 0; j < underlyingIfaces.size(); j++) { + if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) { perInterfaceTotal[j].add(recycle); underlyingIfacesTotal.add(recycle); break; @@ -1515,12 +1516,12 @@ public final class NetworkStats implements Parcelable { * underlyingIfaces} */ private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull List<String> underlyingIfaces, @NonNull Entry tunIfaceTotal, @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { // Traffic that should be moved off of each underlying interface for tunUid (see // deductTrafficFromVpnApp below). - final Entry[] moved = new Entry[underlyingIfaces.length]; - for (int i = 0; i < underlyingIfaces.length; i++) { + final Entry[] moved = new Entry[underlyingIfaces.size()]; + for (int i = 0; i < underlyingIfaces.size(); i++) { moved[i] = new Entry(); } @@ -1582,8 +1583,8 @@ public final class NetworkStats implements Parcelable { } // In a second pass, distribute these values across interfaces in the proportion that // each interface represents of the total traffic of the underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - tmpEntry.iface = underlyingIfaces[j]; + for (int j = 0; j < underlyingIfaces.size(); j++) { + tmpEntry.iface = underlyingIfaces.get(j); tmpEntry.rxBytes = 0; // Reset 'set' to correct value since it gets updated when adding debug info below. tmpEntry.set = set[i]; @@ -1638,14 +1639,14 @@ public final class NetworkStats implements Parcelable { private void deductTrafficFromVpnApp( int tunUid, - @NonNull String[] underlyingIfaces, + @NonNull List<String> underlyingIfaces, @NonNull Entry[] moved) { - for (int i = 0; i < underlyingIfaces.length; i++) { + for (int i = 0; i < underlyingIfaces.size(); i++) { moved[i].uid = tunUid; // Add debug info moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; - moved[i].iface = underlyingIfaces[i]; + moved[i].iface = underlyingIfaces.get(i); moved[i].metered = METERED_ALL; moved[i].roaming = ROAMING_ALL; moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; @@ -1658,7 +1659,7 @@ public final class NetworkStats implements Parcelable { // METERED_NO, which should be the case as it comes directly from the /proc file. // We only blend in the roaming data after applying these adjustments, by checking the // NetworkIdentity of the underlying iface. - final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, + final int idxVpnBackground = findIndex(underlyingIfaces.get(i), tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); if (idxVpnBackground != -1) { // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed @@ -1666,7 +1667,7 @@ public final class NetworkStats implements Parcelable { tunSubtract(idxVpnBackground, this, moved[i]); } - final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, + final int idxVpnForeground = findIndex(underlyingIfaces.get(i), tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved[i]); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index c83dd99c2a3b..d3c89574944f 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -82,6 +82,24 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_WIFI_WILDCARD = 7; public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + public static final int MATCH_CARRIER = 10; + + /** + * Value of the match rule of the subscriberId to match networks with specific subscriberId. + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; + /** + * Value of the match rule of the subscriberId to match networks with any subscriberId which + * includes null and non-null. + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; + + /** + * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that + * should be fixed), so it's not possible to want to match null vs + * non-null. Therefore it's fine to use null as a sentinel for Network ID. + */ + public static final String WIFI_NETWORKID_ALL = null; /** * Include all network types when filtering. This is meant to merge in with the @@ -125,6 +143,7 @@ public class NetworkTemplate implements Parcelable { case MATCH_WIFI_WILDCARD: case MATCH_BLUETOOTH: case MATCH_PROXY: + case MATCH_CARRIER: return true; default: @@ -168,10 +187,12 @@ public class NetworkTemplate implements Parcelable { @NetworkType int ratType) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -189,6 +210,8 @@ public class NetworkTemplate implements Parcelable { */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifiWildcard() { + // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL + // and SUBSCRIBER_ID_MATCH_RULE_ALL. return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } @@ -202,8 +225,27 @@ public class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the * given SSID. */ - public static NetworkTemplate buildTemplateWifi(String networkId) { - return new NetworkTemplate(MATCH_WIFI, null, networkId); + public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) { + Objects.requireNonNull(networkId); + return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */, + new String[] { null } /* matchSubscriberIds */, + networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_ALL); + } + + /** + * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID, + * and IMSI. + * + * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID. + */ + public static NetworkTemplate buildTemplateWifi(@Nullable String networkId, + @Nullable String subscriberId) { + return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, + networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -231,6 +273,14 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_PROXY, null, null); } + /** + * Template to match all carrier networks with the given IMSI. + */ + public static NetworkTemplate buildTemplateCarrier(@NonNull String subscriberId) { + Objects.requireNonNull(subscriberId); + return new NetworkTemplate(MATCH_CARRIER, subscriberId, null); + } + private final int mMatchRule; private final String mSubscriberId; @@ -251,10 +301,26 @@ public class NetworkTemplate implements Parcelable { private final int mRoaming; private final int mDefaultNetwork; private final int mSubType; + private final int mSubscriberIdMatchRule; // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. private final int mOemManaged; + private void checkValidSubscriberIdMatchRule() { + switch (mMatchRule) { + case MATCH_MOBILE: + case MATCH_CARRIER: + // MOBILE and CARRIER templates must always specify a subscriber ID. + if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + throw new IllegalArgumentException("Invalid SubscriberIdMatchRule" + + "on match rule: " + getMatchRuleName(mMatchRule)); + } + return; + default: + return; + } + } + @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -263,14 +329,25 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } + // TODO: Remove it after updating all of the caller. public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, int oemManaged) { + this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming, + defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT); + } + + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId, int metered, int roaming, int defaultNetwork, int subType, + int oemManaged, int subscriberIdMatchRule) { mMatchRule = matchRule; mSubscriberId = subscriberId; + // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when + // mSubscriberId is null mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; mMetered = metered; @@ -278,7 +355,8 @@ public class NetworkTemplate implements Parcelable { mDefaultNetwork = defaultNetwork; mSubType = subType; mOemManaged = oemManaged; - + mSubscriberIdMatchRule = subscriberIdMatchRule; + checkValidSubscriberIdMatchRule(); if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule + " will not match any identity."); @@ -295,6 +373,7 @@ public class NetworkTemplate implements Parcelable { mDefaultNetwork = in.readInt(); mSubType = in.readInt(); mOemManaged = in.readInt(); + mSubscriberIdMatchRule = in.readInt(); } @Override @@ -308,6 +387,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mDefaultNetwork); dest.writeInt(mSubType); dest.writeInt(mOemManaged); + dest.writeInt(mSubscriberIdMatchRule); } @Override @@ -346,13 +426,15 @@ public class NetworkTemplate implements Parcelable { if (mOemManaged != OEM_MANAGED_ALL) { builder.append(", oemManaged=").append(mOemManaged); } + builder.append(", subscriberIdMatchRule=") + .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule)); return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork, mSubType, mOemManaged); + mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule); } @Override @@ -366,11 +448,23 @@ public class NetworkTemplate implements Parcelable { && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork && mSubType == other.mSubType - && mOemManaged == other.mOemManaged; + && mOemManaged == other.mOemManaged + && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule; } return false; } + private String subscriberIdMatchRuleToString(int rule) { + switch (rule) { + case SUBSCRIBER_ID_MATCH_RULE_EXACT: + return "EXACT_MATCH"; + case SUBSCRIBER_ID_MATCH_RULE_ALL: + return "ALL"; + default: + return "Unknown rule " + rule; + } + } + public boolean isMatchRuleMobile() { switch (mMatchRule) { case MATCH_MOBILE: @@ -386,6 +480,14 @@ public class NetworkTemplate implements Parcelable { case MATCH_MOBILE_WILDCARD: case MATCH_WIFI_WILDCARD: return false; + case MATCH_CARRIER: + return mSubscriberId != null; + case MATCH_WIFI: + if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + return false; + } + return true; default: return true; } @@ -405,6 +507,10 @@ public class NetworkTemplate implements Parcelable { return mNetworkId; } + public int getSubscriberIdMatchRule() { + return mSubscriberIdMatchRule; + } + /** * Test if given {@link NetworkIdentity} matches this template. */ @@ -429,6 +535,8 @@ public class NetworkTemplate implements Parcelable { return matchesBluetooth(ident); case MATCH_PROXY: return matchesProxy(ident); + case MATCH_CARRIER: + return matchesCarrier(ident); default: // We have no idea what kind of network template we are, so we // just claim not to match anything. @@ -466,8 +574,23 @@ public class NetworkTemplate implements Parcelable { || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); } - public boolean matchesSubscriberId(String subscriberId) { - return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + /** + * Check if this template matches {@code subscriberId}. Returns true if this + * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a + * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. + */ + public boolean matchesSubscriberId(@Nullable String subscriberId) { + return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL + || ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + } + + /** + * Check if network with matching SSID. Returns true when the SSID matches, or when + * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}. + */ + private boolean matchesWifiNetworkId(@Nullable String networkId) { + return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId)); } /** @@ -566,8 +689,8 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: - return Objects.equals( - sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); + return matchesSubscriberId(ident.mSubscriberId) + && matchesWifiNetworkId(ident.mNetworkId); default: return false; } @@ -583,6 +706,15 @@ public class NetworkTemplate implements Parcelable { return false; } + /** + * Check if matches carrier network. The carrier networks means it includes the subscriberId. + */ + private boolean matchesCarrier(NetworkIdentity ident) { + return ident.mSubscriberId != null + && !ArrayUtils.isEmpty(mMatchSubscriberIds) + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + } + private boolean matchesMobileWildcard(NetworkIdentity ident) { if (ident.mType == TYPE_WIMAX) { return true; @@ -635,6 +767,8 @@ public class NetworkTemplate implements Parcelable { return "BLUETOOTH"; case MATCH_PROXY: return "PROXY"; + case MATCH_CARRIER: + return "CARRIER"; default: return "UNKNOWN(" + matchRule + ")"; } diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java index 7bf923123910..33f9375c03bf 100644 --- a/core/java/android/net/UnderlyingNetworkInfo.java +++ b/core/java/android/net/UnderlyingNetworkInfo.java @@ -37,36 +37,56 @@ import java.util.Objects; @SystemApi(client = MODULE_LIBRARIES) public final class UnderlyingNetworkInfo implements Parcelable { /** The owner of this network. */ - public final int ownerUid; + private final int mOwnerUid; + /** The interface name of this network. */ @NonNull - public final String iface; + private final String mIface; + /** The names of the interfaces underlying this network. */ @NonNull - public final List<String> underlyingIfaces; + private final List<String> mUnderlyingIfaces; public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface, @NonNull List<String> underlyingIfaces) { Objects.requireNonNull(iface); Objects.requireNonNull(underlyingIfaces); - this.ownerUid = ownerUid; - this.iface = iface; - this.underlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); + mOwnerUid = ownerUid; + mIface = iface; + mUnderlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); } private UnderlyingNetworkInfo(@NonNull Parcel in) { - this.ownerUid = in.readInt(); - this.iface = in.readString(); - this.underlyingIfaces = new ArrayList<>(); - in.readList(this.underlyingIfaces, null /*classLoader*/); + mOwnerUid = in.readInt(); + mIface = in.readString(); + List<String> underlyingIfaces = new ArrayList<>(); + in.readList(underlyingIfaces, null /*classLoader*/); + mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces); + } + + /** Get the owner of this network. */ + public int getOwnerUid() { + return mOwnerUid; + } + + /** Get the interface name of this network. */ + @NonNull + public String getInterface() { + return mIface; + } + + /** Get the names of the interfaces underlying this network. */ + @NonNull + public List<String> getUnderlyingInterfaces() { + return mUnderlyingIfaces; } @Override public String toString() { return "UnderlyingNetworkInfo{" - + "ownerUid=" + ownerUid - + ", iface='" + iface + '\'' - + ", underlyingIfaces='" + underlyingIfaces.toString() + '\'' + + "ownerUid=" + mOwnerUid + + ", iface='" + mIface + '\'' + + ", underlyingIfaces='" + mUnderlyingIfaces.toString() + '\'' + '}'; } @@ -77,9 +97,9 @@ public final class UnderlyingNetworkInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(ownerUid); - dest.writeString(iface); - dest.writeList(underlyingIfaces); + dest.writeInt(mOwnerUid); + dest.writeString(mIface); + dest.writeList(mUnderlyingIfaces); } @NonNull @@ -103,13 +123,13 @@ public final class UnderlyingNetworkInfo implements Parcelable { if (this == o) return true; if (!(o instanceof UnderlyingNetworkInfo)) return false; final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; - return ownerUid == that.ownerUid - && Objects.equals(iface, that.iface) - && Objects.equals(underlyingIfaces, that.underlyingIfaces); + return mOwnerUid == that.getOwnerUid() + && Objects.equals(mIface, that.getInterface()) + && Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces()); } @Override public int hashCode() { - return Objects.hash(ownerUid, iface, underlyingIfaces); + return Objects.hash(mOwnerUid, mIface, mUnderlyingIfaces); } } diff --git a/core/java/android/net/vcn/OWNERS b/core/java/android/net/vcn/OWNERS index 33b9f0f75f81..2441e772468c 100644 --- a/core/java/android/net/vcn/OWNERS +++ b/core/java/android/net/vcn/OWNERS @@ -3,5 +3,5 @@ set noparent benedictwong@google.com ckesting@google.com evitayan@google.com +junyin@google.com nharold@google.com -jchalard@google.com
\ No newline at end of file diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java index d41c0b4fbdb3..caab15251f58 100644 --- a/core/java/android/net/vcn/VcnConfig.java +++ b/core/java/android/net/vcn/VcnConfig.java @@ -52,12 +52,17 @@ public final class VcnConfig implements Parcelable { private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs"; @NonNull private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs; + private static final String IS_TEST_MODE_PROFILE_KEY = "mIsTestModeProfile"; + private final boolean mIsTestModeProfile; + private VcnConfig( @NonNull String packageName, - @NonNull Set<VcnGatewayConnectionConfig> gatewayConnectionConfigs) { + @NonNull Set<VcnGatewayConnectionConfig> gatewayConnectionConfigs, + boolean isTestModeProfile) { mPackageName = packageName; mGatewayConnectionConfigs = Collections.unmodifiableSet(new ArraySet<>(gatewayConnectionConfigs)); + mIsTestModeProfile = isTestModeProfile; validate(); } @@ -77,6 +82,7 @@ public final class VcnConfig implements Parcelable { new ArraySet<>( PersistableBundleUtils.toList( gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new)); + mIsTestModeProfile = in.getBoolean(IS_TEST_MODE_PROFILE_KEY); validate(); } @@ -104,6 +110,15 @@ public final class VcnConfig implements Parcelable { } /** + * Returns whether or not this VcnConfig is restricted to test networks. + * + * @hide + */ + public boolean isTestModeProfile() { + return mIsTestModeProfile; + } + + /** * Serializes this object to a PersistableBundle. * * @hide @@ -119,13 +134,14 @@ public final class VcnConfig implements Parcelable { new ArrayList<>(mGatewayConnectionConfigs), VcnGatewayConnectionConfig::toPersistableBundle); result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle); + result.putBoolean(IS_TEST_MODE_PROFILE_KEY, mIsTestModeProfile); return result; } @Override public int hashCode() { - return Objects.hash(mPackageName, mGatewayConnectionConfigs); + return Objects.hash(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile); } @Override @@ -136,7 +152,8 @@ public final class VcnConfig implements Parcelable { final VcnConfig rhs = (VcnConfig) other; return mPackageName.equals(rhs.mPackageName) - && mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs); + && mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs) + && mIsTestModeProfile == rhs.mIsTestModeProfile; } // Parcelable methods @@ -172,6 +189,8 @@ public final class VcnConfig implements Parcelable { @NonNull private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs = new ArraySet<>(); + private boolean mIsTestModeProfile = false; + public Builder(@NonNull Context context) { Objects.requireNonNull(context, "context was null"); @@ -207,13 +226,29 @@ public final class VcnConfig implements Parcelable { } /** + * Restricts this VcnConfig to matching with test networks (only). + * + * <p>This method is for testing only, and must not be used by apps. Calling {@link + * VcnManager#setVcnConfig(ParcelUuid, VcnConfig)} with a VcnConfig where test-network usage + * is enabled will require the MANAGE_TEST_NETWORKS permission. + * + * @return this {@link Builder} instance, for chaining + * @hide + */ + @NonNull + public Builder setIsTestModeProfile() { + mIsTestModeProfile = true; + return this; + } + + /** * Builds and validates the VcnConfig. * * @return an immutable VcnConfig instance */ @NonNull public VcnConfig build() { - return new VcnConfig(mPackageName, mGatewayConnectionConfigs); + return new VcnConfig(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile); } } } diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index adcbe2542ab6..d59ad6f88864 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -15,6 +15,8 @@ */ package android.net.vcn; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; + import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntDef; @@ -24,7 +26,7 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.TunnelConnectionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils; import android.os.PersistableBundle; import android.util.ArraySet; @@ -136,7 +138,7 @@ public final class VcnGatewayConnectionConfig { * <p>To ensure the device is not constantly being woken up, this retry interval MUST be greater * than this value. * - * @see {@link Builder#setRetryIntervalsMs()} + * @see {@link Builder#setRetryIntervalsMillis()} */ private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15); @@ -154,14 +156,11 @@ public final class VcnGatewayConnectionConfig { @NonNull private final String mGatewayConnectionName; private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams"; - @NonNull private TunnelConnectionParams mTunnelConnectionParams; + @NonNull private IkeTunnelConnectionParams mTunnelConnectionParams; private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet<Integer> mExposedCapabilities; - private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities"; - @NonNull private final SortedSet<Integer> mUnderlyingCapabilities; - private static final String MAX_MTU_KEY = "mMaxMtu"; private final int mMaxMtu; @@ -171,15 +170,13 @@ public final class VcnGatewayConnectionConfig { /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ private VcnGatewayConnectionConfig( @NonNull String gatewayConnectionName, - @NonNull TunnelConnectionParams tunnelConnectionParams, + @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set<Integer> exposedCapabilities, - @NonNull Set<Integer> underlyingCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; mExposedCapabilities = new TreeSet(exposedCapabilities); - mUnderlyingCapabilities = new TreeSet(underlyingCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; @@ -196,16 +193,12 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle exposedCapsBundle = in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY); - final PersistableBundle underlyingCapsBundle = - in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY); mTunnelConnectionParams = TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle); mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); - mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList( - underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); @@ -271,7 +264,7 @@ public final class VcnGatewayConnectionConfig { * @hide */ @NonNull - public TunnelConnectionParams getTunnelConnectionParams() { + public IkeTunnelConnectionParams getTunnelConnectionParams() { return mTunnelConnectionParams; } @@ -305,42 +298,12 @@ public final class VcnGatewayConnectionConfig { } /** - * Returns all capabilities required of underlying networks. - * - * <p>The returned integer-value capabilities will be sorted in ascending numerical order. - * - * @see Builder#addRequiredUnderlyingCapability(int) - * @see Builder#removeRequiredUnderlyingCapability(int) - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - public int[] getRequiredUnderlyingCapabilities() { - // Sorted set guarantees ordering - return ArrayUtils.convertToIntArray(new ArrayList<>(mUnderlyingCapabilities)); - } - - /** - * Returns all capabilities required of underlying networks. - * - * <p>Left to prevent the need to make major changes while changes are actively in flight. - * - * @deprecated use getRequiredUnderlyingCapabilities() instead - * @hide - */ - @Deprecated - @NonNull - public Set<Integer> getAllUnderlyingCapabilities() { - return Collections.unmodifiableSet(mUnderlyingCapabilities); - } - - /** * Retrieves the configured retry intervals. * - * @see Builder#setRetryIntervalsMs(long[]) + * @see Builder#setRetryIntervalsMillis(long[]) */ @NonNull - public long[] getRetryIntervalsMs() { + public long[] getRetryIntervalsMillis() { return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); } @@ -370,15 +333,10 @@ public final class VcnGatewayConnectionConfig { PersistableBundleUtils.fromList( new ArrayList<>(mExposedCapabilities), PersistableBundleUtils.INTEGER_SERIALIZER); - final PersistableBundle underlyingCapsBundle = - PersistableBundleUtils.fromList( - new ArrayList<>(mUnderlyingCapabilities), - PersistableBundleUtils.INTEGER_SERIALIZER); result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName); result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle); result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle); - result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle); result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs); result.putInt(MAX_MTU_KEY, mMaxMtu); @@ -390,7 +348,6 @@ public final class VcnGatewayConnectionConfig { return Objects.hash( mGatewayConnectionName, mExposedCapabilities, - mUnderlyingCapabilities, Arrays.hashCode(mRetryIntervalsMs), mMaxMtu); } @@ -404,7 +361,6 @@ public final class VcnGatewayConnectionConfig { final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other; return mGatewayConnectionName.equals(rhs.mGatewayConnectionName) && mExposedCapabilities.equals(rhs.mExposedCapabilities) - && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities) && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs) && mMaxMtu == rhs.mMaxMtu; } @@ -414,9 +370,8 @@ public final class VcnGatewayConnectionConfig { */ public static final class Builder { @NonNull private final String mGatewayConnectionName; - @NonNull private final TunnelConnectionParams mTunnelConnectionParams; + @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams; @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet(); - @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; private int mMaxMtu = DEFAULT_MAX_MTU; @@ -432,15 +387,21 @@ public final class VcnGatewayConnectionConfig { * VcnConfig} must be given a unique name. This name is used by the caller to * distinguish between VcnGatewayConnectionConfigs configured on a single {@link * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations. - * @param tunnelConnectionParams the tunnel connection configuration - * @see TunnelConnectionParams + * @param tunnelConnectionParams the IKE tunnel connection configuration + * @throws IllegalArgumentException if the provided IkeTunnelConnectionParams is not + * configured to support MOBIKE + * @see IkeTunnelConnectionParams * @see VcnManager.VcnStatusCallback#onGatewayConnectionError */ public Builder( @NonNull String gatewayConnectionName, - @NonNull TunnelConnectionParams tunnelConnectionParams) { + @NonNull IkeTunnelConnectionParams tunnelConnectionParams) { Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null"); Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null"); + if (!tunnelConnectionParams.getIkeSessionParams().hasIkeOption(IKE_OPTION_MOBIKE)) { + throw new IllegalArgumentException( + "MOBIKE must be configured for the provided IkeSessionParams"); + } mGatewayConnectionName = gatewayConnectionName; mTunnelConnectionParams = tunnelConnectionParams; @@ -482,51 +443,6 @@ public final class VcnGatewayConnectionConfig { } /** - * Require a capability for Networks underlying this VCN Gateway Connection. - * - * @param underlyingCapability the capability that a network MUST have in order to be an - * underlying network for this VCN Gateway Connection. - * @return this {@link Builder} instance, for chaining - * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying - * networks - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - public Builder addRequiredUnderlyingCapability( - @VcnSupportedCapability int underlyingCapability) { - checkValidCapability(underlyingCapability); - - mUnderlyingCapabilities.add(underlyingCapability); - return this; - } - - /** - * Remove a requirement of a capability for Networks underlying this VCN Gateway Connection. - * - * <p>Calling this method will allow Networks that do NOT have this capability to be - * selected as an underlying network for this VCN Gateway Connection. However, underlying - * networks MAY still have the removed capability. - * - * @param underlyingCapability the capability that a network DOES NOT need to have in order - * to be an underlying network for this VCN Gateway Connection. - * @return this {@link Builder} instance, for chaining - * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying - * networks - * @hide - */ - // TODO(b/182219992): Remove, and add when per-transport capabilities are supported - @NonNull - @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap - public Builder removeRequiredUnderlyingCapability( - @VcnSupportedCapability int underlyingCapability) { - checkValidCapability(underlyingCapability); - - mUnderlyingCapabilities.remove(underlyingCapability); - return this; - } - - /** * Set the retry interval between VCN establishment attempts upon successive failures. * * <p>The last retry interval will be repeated until safe mode is entered, or a connection @@ -550,7 +466,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnManager for additional discussion on fail-safe mode */ @NonNull - public Builder setRetryIntervalsMs(@NonNull long[] retryIntervalsMs) { + public Builder setRetryIntervalsMillis(@NonNull long[] retryIntervalsMs) { validateRetryInterval(retryIntervalsMs); mRetryIntervalsMs = retryIntervalsMs; @@ -590,7 +506,6 @@ public final class VcnGatewayConnectionConfig { mGatewayConnectionName, mTunnelConnectionParams, mExposedCapabilities, - mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu); } diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 9d1c1ff898e7..390c3b9453c2 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -74,6 +74,36 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); + /** + * Key for WiFi entry RSSI thresholds + * + * <p>The VCN will only migrate to a Carrier WiFi network that has a signal strength greater + * than, or equal to this threshold. + * + * <p>WARNING: The VCN does not listen for changes to this key made after VCN startup. + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY = + "vcn_network_selection_wifi_entry_rssi_threshold"; + + /** + * Key for WiFi entry RSSI thresholds + * + * <p>If the VCN's selected Carrier WiFi network has a signal strength less than this threshold, + * the VCN will attempt to migrate away from the Carrier WiFi network. + * + * <p>WARNING: The VCN does not listen for changes to this key made after VCN startup. + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY = + "vcn_network_selection_wifi_exit_rssi_threshold"; + + // TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz + private static final Map< VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.java b/core/java/android/net/vcn/VcnNetworkPolicyResult.java index 5e938200639c..14e70cfeb18a 100644 --- a/core/java/android/net/vcn/VcnNetworkPolicyResult.java +++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.java @@ -87,6 +87,16 @@ public final class VcnNetworkPolicyResult implements Parcelable { && mNetworkCapabilities.equals(that.mNetworkCapabilities); } + @Override + public String toString() { + return "VcnNetworkPolicyResult { " + + "mIsTeardownRequested = " + + mIsTearDownRequested + + ", mNetworkCapabilities" + + mNetworkCapabilities + + " }"; + } + /** {@inheritDoc} */ @Override public int describeContents() { diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java index 4d8cf91621ba..1f1818420b56 100644 --- a/core/java/android/net/vcn/VcnTransportInfo.java +++ b/core/java/android/net/vcn/VcnTransportInfo.java @@ -16,6 +16,9 @@ package android.net.vcn; +import static android.net.NetworkCapabilities.REDACT_NONE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + import android.annotation.NonNull; import android.annotation.Nullable; import android.net.TransportInfo; @@ -37,6 +40,9 @@ import java.util.Objects; * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. If the underlying Network is Cellular, the WifiInfo * will be {@code null}. * + * <p>Receipt of a VcnTransportInfo requires the NETWORK_SETTINGS permission; else the entire + * VcnTransportInfo instance will be redacted. + * * @hide */ public class VcnTransportInfo implements TransportInfo, Parcelable { @@ -44,7 +50,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { private final int mSubId; public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { - this(wifiInfo, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + this(wifiInfo, INVALID_SUBSCRIPTION_ID); } public VcnTransportInfo(int subId) { @@ -52,11 +58,6 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { } private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) { - if (wifiInfo == null && subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - throw new IllegalArgumentException( - "VcnTransportInfo requires either non-null WifiInfo or valid subId"); - } - mWifiInfo = wifiInfo; mSubId = subId; } @@ -80,7 +81,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. * * @return the Subscription ID if a cellular underlying Network is present, else {@link - * android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID}. + * android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}. */ public int getSubId() { return mSubId; @@ -95,7 +96,6 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { public boolean equals(Object o) { if (!(o instanceof VcnTransportInfo)) return false; final VcnTransportInfo that = (VcnTransportInfo) o; - return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId; } @@ -105,17 +105,37 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return 0; } + @Override + @NonNull + public TransportInfo makeCopy(long redactions) { + return new VcnTransportInfo( + (mWifiInfo == null) ? null : mWifiInfo.makeCopy(redactions), mSubId); + } + + @Override + public long getApplicableRedactions() { + return (mWifiInfo == null) ? REDACT_NONE : mWifiInfo.getApplicableRedactions(); + } + /** {@inheritDoc} */ @Override - public void writeToParcel(@NonNull Parcel dest, int flags) {} + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSubId); + dest.writeParcelable(mWifiInfo, flags); + } + + @Override + public String toString() { + return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }"; + } /** Implement the Parcelable interface */ public static final @NonNull Creator<VcnTransportInfo> CREATOR = new Creator<VcnTransportInfo>() { public VcnTransportInfo createFromParcel(Parcel in) { - // return null instead of a default VcnTransportInfo to avoid leaking - // information about this being a VCN Network (instead of macro cellular, etc) - return null; + final int subId = in.readInt(); + final WifiInfo wifiInfo = in.readParcelable(null); + return new VcnTransportInfo(wifiInfo, subId); } public VcnTransportInfo[] newArray(int size) { diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java index b47d5642419e..b0d4f3be248f 100644 --- a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java +++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -85,6 +85,11 @@ public final class VcnUnderlyingNetworkPolicy implements Parcelable { return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult); } + @Override + public String toString() { + return mVcnNetworkPolicyResult.toString(); + } + /** {@inheritDoc} */ @Override public int describeContents() { diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java index 690e4e76ea5f..4bc5b49aa207 100644 --- a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java +++ b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java @@ -16,7 +16,6 @@ package android.net.vcn.persistablebundleutils; import android.annotation.NonNull; -import android.net.TunnelConnectionParams; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; @@ -25,7 +24,7 @@ import android.os.PersistableBundle; import java.util.Objects; /** - * Utility class to convert TunnelConnectionParams to/from PersistableBundle + * Utility class to convert Tunnel Connection Params to/from PersistableBundle * * @hide */ @@ -34,30 +33,28 @@ public final class TunnelConnectionParamsUtils { private static final String PARAMS_TYPE_IKE = "IKE"; - /** Serializes an TunnelConnectionParams to a PersistableBundle. */ + /** Serializes an IkeTunnelConnectionParams to a PersistableBundle. */ @NonNull - public static PersistableBundle toPersistableBundle(@NonNull TunnelConnectionParams params) { + public static PersistableBundle toPersistableBundle(@NonNull IkeTunnelConnectionParams params) { final PersistableBundle result = new PersistableBundle(); - if (params instanceof IkeTunnelConnectionParams) { - result.putPersistableBundle( - PARAMS_TYPE_IKE, - IkeTunnelConnectionParamsUtils.serializeIkeParams( - (IkeTunnelConnectionParams) params)); - return result; - } else { - throw new UnsupportedOperationException("Invalid TunnelConnectionParams type"); - } + result.putPersistableBundle( + PARAMS_TYPE_IKE, + IkeTunnelConnectionParamsUtils.serializeIkeParams( + (IkeTunnelConnectionParams) params)); + return result; } - /** Constructs an TunnelConnectionParams by deserializing a PersistableBundle. */ + /** Constructs an IkeTunnelConnectionParams by deserializing a PersistableBundle. */ @NonNull - public static TunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) { + public static IkeTunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle was null"); if (in.keySet().size() != EXPECTED_BUNDLE_KEY_CNT) { throw new IllegalArgumentException( - "Expect PersistableBundle to have one element but found: " + in.keySet()); + String.format( + "Expect PersistableBundle to have %d element but found: %d", + EXPECTED_BUNDLE_KEY_CNT, in.keySet())); } if (in.get(PARAMS_TYPE_IKE) != null) { @@ -66,7 +63,7 @@ public final class TunnelConnectionParamsUtils { } throw new IllegalArgumentException( - "Invalid TunnelConnectionParams type " + in.keySet().iterator().next()); + "Invalid Tunnel Connection Params type " + in.keySet().iterator().next()); } private static final class IkeTunnelConnectionParamsUtils { diff --git a/core/java/android/nfc/NfcControllerAlwaysOnListener.java b/core/java/android/nfc/NfcControllerAlwaysOnListener.java index 96707bb432db..6ae58fd38cbe 100644 --- a/core/java/android/nfc/NfcControllerAlwaysOnListener.java +++ b/core/java/android/nfc/NfcControllerAlwaysOnListener.java @@ -52,6 +52,14 @@ public class NfcControllerAlwaysOnListener extends INfcControllerAlwaysOnListene */ public void register(@NonNull Executor executor, @NonNull ControllerAlwaysOnListener listener) { + try { + if (!mAdapter.isControllerAlwaysOnSupported()) { + return; + } + } catch (RemoteException e) { + Log.w(TAG, "Failed to register"); + return; + } synchronized (this) { if (mListenerMap.containsKey(listener)) { return; @@ -75,6 +83,14 @@ public class NfcControllerAlwaysOnListener extends INfcControllerAlwaysOnListene * @param listener user implementation of the {@link ControllerAlwaysOnListener} */ public void unregister(@NonNull ControllerAlwaysOnListener listener) { + try { + if (!mAdapter.isControllerAlwaysOnSupported()) { + return; + } + } catch (RemoteException e) { + Log.w(TAG, "Failed to unregister"); + return; + } synchronized (this) { if (!mListenerMap.containsKey(listener)) { return; diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index e47ffcc4ff4c..5017d9e8d905 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -424,7 +424,8 @@ public class Build { * Magic version number for a current development build, which has * not yet turned into an official release. */ - public static final int CUR_DEVELOPMENT = VMRuntime.SDK_VERSION_CUR_DEVELOPMENT; + // This must match VMRuntime.SDK_VERSION_CUR_DEVELOPMENT. + public static final int CUR_DEVELOPMENT = 10000; /** * October 2008: The original, first, version of Android. Yay! @@ -1311,6 +1312,7 @@ public class Build { * selinux into "permissive" mode in particular. * @hide */ + @UnsupportedAppUsage public static final boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1; diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 1e60f74dd3d3..a7516a428ff0 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -74,8 +74,9 @@ public final class Debug * * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + // This must match VMDebug.TRACE_COUNT_ALLOCS. @Deprecated - public static final int TRACE_COUNT_ALLOCS = VMDebug.TRACE_COUNT_ALLOCS; + public static final int TRACE_COUNT_ALLOCS = 1; /** * Flags for printLoadedClasses(). Default behavior is to only show diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl index 9368b68a91c6..88bdb7f6f00b 100644 --- a/core/java/android/os/IRecoverySystem.aidl +++ b/core/java/android/os/IRecoverySystem.aidl @@ -23,6 +23,7 @@ import android.os.IRecoverySystemProgressListener; /** @hide */ interface IRecoverySystem { + boolean allocateSpaceForUpdate(in String packageFilePath); boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener); boolean setupBcb(in String command); boolean clearBcb(); diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index d9665953dceb..cd02d297270a 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -63,3 +63,6 @@ per-file *Zygote* = file:/ZYGOTE_OWNERS # RecoverySystem per-file *Recovery* = file:/services/core/java/com/android/server/recoverysystem/OWNERS + +# Bugreporting +per-file Bugreport* = file:/platform/frameworks/native:/cmds/dumpstate/OWNERS diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 051447f9219b..944b71700450 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -672,6 +672,14 @@ public class RecoverySystem { if (!rs.setupBcb(command)) { throw new IOException("Setup BCB failed"); } + try { + if (!rs.allocateSpaceForUpdate(packageFile)) { + throw new IOException("Failed to allocate space for update " + + packageFile.getAbsolutePath()); + } + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } // Having set up the BCB (bootloader control block), go ahead and reboot PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); @@ -1392,6 +1400,13 @@ public class RecoverySystem { } /** + * Talks to RecoverySystemService via Binder to allocate space + */ + private boolean allocateSpaceForUpdate(File packageFile) throws RemoteException { + return mService.allocateSpaceForUpdate(packageFile.getAbsolutePath()); + } + + /** * Talks to RecoverySystemService via Binder to clear up the BCB. */ private boolean clearBcb() { diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java index 7af8f71aa4aa..bf0b655fe574 100644 --- a/core/java/android/os/VintfObject.java +++ b/core/java/android/os/VintfObject.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.NonNull; import android.annotation.TestApi; import android.util.Slog; @@ -112,6 +113,15 @@ public class VintfObject { public static native String getSepolicyVersion(); /** + * @return the PLATFORM_SEPOLICY_VERSION build flag available in framework + * compatibility matrix. + * + * @hide + */ + @TestApi + public static native @NonNull String getPlatformSepolicyVersion(); + + /** * @return a list of VNDK snapshots supported by the framework, as * specified in framework manifest. For example, * [("27", ["libjpeg.so", "libbase.so"]), diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java index c19884805507..f5081012fe4c 100644 --- a/core/java/android/print/PrintAttributes.java +++ b/core/java/android/print/PrintAttributes.java @@ -837,8 +837,8 @@ public final class PrintAttributes implements Parcelable { new MediaSize("JPN_YOU4", "android", R.string.mediasize_japanese_you4, 4134, 9252); /** Japanese Photo L media size: 89mm x 127mm (3.5 x 5") */ - public static final @NonNull MediaSize OE_PHOTO_L = - new MediaSize("OE_PHOTO_L", "android", + public static final @NonNull MediaSize JPN_OE_PHOTO_L = + new MediaSize("JPN_OE_PHOTO_L", "android", R.string.mediasize_japanese_l, 3500, 5000); private final @NonNull String mId; diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index a3a910acae63..d22f7e3bfd6e 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -5327,5 +5327,29 @@ public final class Telephony { * @hide */ public static final String COLUMN_RCS_CONFIG = "rcs_config"; + + /** + * TelephonyProvider column name for device to device sharing status. + * + * @hide + */ + public static final String COLUMN_D2D_STATUS_SHARING = "d2d_sharing_status"; + + /** + * TelephonyProvider column name for VoIMS provisioning. Default is 0. + * <P>Type: INTEGER </P> + * + * @hide + */ + public static final String COLUMN_VOIMS_OPT_IN_STATUS = "voims_opt_in_status"; + + /** + * TelephonyProvider column name for information selected contacts that allow device to + * device sharing. + * + * @hide + */ + public static final String COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS = + "d2d_sharing_contacts"; } } diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 5a89cdf1d340..0b11aeb1ed65 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -66,9 +66,6 @@ public final class KeymasterDefs { public static final int KM_TAG_CALLER_NONCE = Tag.CALLER_NONCE; // KM_BOOL | 7; public static final int KM_TAG_MIN_MAC_LENGTH = Tag.MIN_MAC_LENGTH; // KM_UINT | 8; - public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = - Tag.BLOB_USAGE_REQUIREMENTS; // KM_ENUM | 705; - public static final int KM_TAG_RSA_PUBLIC_EXPONENT = Tag.RSA_PUBLIC_EXPONENT; // KM_ULONG | 200; public static final int KM_TAG_INCLUDE_UNIQUE_ID = Tag.INCLUDE_UNIQUE_ID; // KM_BOOL | 202; diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java index 50f63f8db304..c75e23807432 100644 --- a/core/java/android/util/JsonReader.java +++ b/core/java/android/util/JsonReader.java @@ -16,7 +16,7 @@ package android.util; -import libcore.internal.StringPool; +import com.android.internal.util.StringPool; import java.io.Closeable; import java.io.EOFException; diff --git a/core/java/android/uwb/AdapterStateListener.java b/core/java/android/uwb/AdapterStateListener.java index b9900951591f..91847f740953 100644 --- a/core/java/android/uwb/AdapterStateListener.java +++ b/core/java/android/uwb/AdapterStateListener.java @@ -68,8 +68,7 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub { mIsRegistered = true; } catch (RemoteException e) { Log.w(TAG, "Failed to register adapter state callback"); - executor.execute(() -> callback.onStateChanged(mAdapterState, - AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN)); + throw e.rethrowFromSystemServer(); } } else { sendCurrentState(callback); @@ -95,6 +94,7 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub { mAdapter.unregisterAdapterStateCallbacks(this); } catch (RemoteException e) { Log.w(TAG, "Failed to unregister AdapterStateCallback with service"); + throw e.rethrowFromSystemServer(); } mIsRegistered = false; } @@ -115,24 +115,24 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub { mAdapter.setEnabled(isEnabled); } catch (RemoteException e) { Log.w(TAG, "Failed to set adapter state"); - sendErrorState(); + throw e.rethrowFromSystemServer(); } } } } - private void sendErrorState() { + /** + * Gets the adapter enabled state + * + * @return integer representing adapter enabled state + */ + public int getAdapterState() { synchronized (this) { - for (AdapterStateCallback callback: mCallbackMap.keySet()) { - Executor executor = mCallbackMap.get(callback); - - final long identity = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onStateChanged( - mAdapterState, mAdapterStateChangeReason)); - } finally { - Binder.restoreCallingIdentity(identity); - } + try { + return mAdapter.getAdapterState(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to get adapter state"); + throw e.rethrowFromSystemServer(); } } } diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl index 5804d04bdba7..e02e5eb25990 100644 --- a/core/java/android/uwb/IUwbAdapter.aidl +++ b/core/java/android/uwb/IUwbAdapter.aidl @@ -158,6 +158,18 @@ interface IUwbAdapter { */ void setEnabled(boolean enabled); + /** + * Returns the current enabled/disabled UWB state. + * + * Possible values are: + * IUwbAdapterState#STATE_DISABLED + * IUwbAdapterState#STATE_ENABLED_ACTIVE + * IUwbAdapterState#STATE_ENABLED_INACTIVE + * + * @return value representing enabled/disabled UWB state. + */ + int getAdapterState(); + /** * The maximum allowed time to open a ranging session. */ diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java index 9116c49d0764..4edecdaad0dd 100644 --- a/core/java/android/uwb/UwbManager.java +++ b/core/java/android/uwb/UwbManager.java @@ -175,7 +175,7 @@ public final class UwbManager { * <p>The provided callback will be invoked by the given {@link Executor}. * * <p>When first registering a callback, the callbacks's - * {@link AdapterStateCallback#onStateChanged(boolean, int)} is immediately invoked to indicate + * {@link AdapterStateCallback#onStateChanged(int, int)} is immediately invoked to indicate * the current state of the underlying UWB adapter with the most recent * {@link AdapterStateCallback.StateChangedReason} that caused the change. * @@ -272,6 +272,21 @@ public final class UwbManager { } /** + * Returns the current enabled/disabled state for UWB. + * + * Possible values are: + * AdapterStateCallback#STATE_DISABLED + * AdapterStateCallback#STATE_ENABLED_INACTIVE + * AdapterStateCallback#STATE_ENABLED_ACTIVE + * + * @return value representing current enabled/disabled state for UWB. + * @hide + */ + public @AdapterStateCallback.State int getAdapterState() { + return mAdapterStateListener.getAdapterState(); + } + + /** * Disables or enables UWB for a user * * @param enabled value representing intent to disable or enable UWB. If true any subsequent diff --git a/core/java/com/android/internal/annotations/GuardedBy.java b/core/java/com/android/internal/annotations/GuardedBy.java deleted file mode 100644 index 0e63214b4f1a..000000000000 --- a/core/java/com/android/internal/annotations/GuardedBy.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation type used to mark a method or field that can only be accessed when - * holding the referenced locks. - */ -@Target({ ElementType.FIELD, ElementType.METHOD }) -@Retention(RetentionPolicy.CLASS) -public @interface GuardedBy { - String[] value(); -} diff --git a/core/java/com/android/internal/annotations/VisibleForTesting.java b/core/java/com/android/internal/annotations/VisibleForTesting.java deleted file mode 100644 index 99512ac68d5d..000000000000 --- a/core/java/com/android/internal/annotations/VisibleForTesting.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Denotes that the class, method or field has its visibility relaxed so - * that unit tests can access it. - * <p/> - * The <code>visibility</code> argument can be used to specific what the original - * visibility should have been if it had not been made public or package-private for testing. - * The default is to consider the element private. - */ -@Retention(RetentionPolicy.CLASS) -public @interface VisibleForTesting { - /** - * Intended visibility if the element had not been made public or package-private for - * testing. - */ - enum Visibility { - /** The element should be considered protected. */ - PROTECTED, - /** The element should be considered package-private. */ - PACKAGE, - /** The element should be considered private. */ - PRIVATE - } - - /** - * Intended visibility if the element had not been made public or package-private for testing. - * If not specified, one should assume the element originally intended to be private. - */ - Visibility visibility() default Visibility.PRIVATE; -} diff --git a/core/java/com/android/internal/app/procstats/OWNERS b/core/java/com/android/internal/app/procstats/OWNERS new file mode 100644 index 000000000000..72c0a9e6e90c --- /dev/null +++ b/core/java/com/android/internal/app/procstats/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/am/OWNERS diff --git a/core/java/com/android/internal/colorextraction/OWNERS b/core/java/com/android/internal/colorextraction/OWNERS new file mode 100644 index 000000000000..ffade1ec4ebd --- /dev/null +++ b/core/java/com/android/internal/colorextraction/OWNERS @@ -0,0 +1,3 @@ +dupin@google.com +cinek@google.com +jamesoleary@google.com diff --git a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java index 36bc22906695..182dba71d0d7 100644 --- a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java +++ b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java @@ -39,14 +39,14 @@ public final class CompatibilityChangeConfig implements Parcelable { * Changes forced to be enabled. */ public Set<Long> enabledChanges() { - return mChangeConfig.forceEnabledSet(); + return mChangeConfig.getEnabledSet(); } /** * Changes forced to be disabled. */ public Set<Long> disabledChanges() { - return mChangeConfig.forceDisabledSet(); + return mChangeConfig.getDisabledSet(); } /** @@ -84,8 +84,8 @@ public final class CompatibilityChangeConfig implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - long[] enabled = mChangeConfig.forceEnabledChangesArray(); - long[] disabled = mChangeConfig.forceDisabledChangesArray(); + long[] enabled = mChangeConfig.getEnabledChangesArray(); + long[] disabled = mChangeConfig.getDisabledChangesArray(); dest.writeLongArray(enabled); dest.writeLongArray(disabled); diff --git a/core/java/com/android/internal/annotations/VisibleForNative.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.aidl index e6a3fc67b7d3..441e553e4d88 100644 --- a/core/java/com/android/internal/annotations/VisibleForNative.java +++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,6 @@ * limitations under the License. */ -package com.android.internal.annotations; +package com.android.internal.compat; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Denotes that the class, method or field has its visibility relaxed so - * that native code can access it. - */ -@Retention(RetentionPolicy.CLASS) -public @interface VisibleForNative { -} +parcelable CompatibilityOverridesToRemoveConfig; diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java new file mode 100644 index 000000000000..642f79ca7afa --- /dev/null +++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.compat; + + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.HashSet; +import java.util.Set; + +/** + * Parcelable containing compat config change IDs for which to remove overrides for a given + * application. + * @hide + */ +public final class CompatibilityOverridesToRemoveConfig implements Parcelable { + public final Set<Long> changeIds; + + public CompatibilityOverridesToRemoveConfig(Set<Long> changeIds) { + this.changeIds = changeIds; + } + + private CompatibilityOverridesToRemoveConfig(Parcel in) { + int keyCount = in.readInt(); + changeIds = new HashSet<>(); + for (int i = 0; i < keyCount; i++) { + changeIds.add(in.readLong()); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(changeIds.size()); + for (Long changeId : changeIds) { + dest.writeLong(changeId); + } + } + + public static final Creator<CompatibilityOverridesToRemoveConfig> CREATOR = + new Creator<CompatibilityOverridesToRemoveConfig>() { + + @Override + public CompatibilityOverridesToRemoveConfig createFromParcel(Parcel in) { + return new CompatibilityOverridesToRemoveConfig(in); + } + + @Override + public CompatibilityOverridesToRemoveConfig[] newArray(int size) { + return new CompatibilityOverridesToRemoveConfig[size]; + } + }; +} diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index 78d1d22c401e..c9f170421e7b 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -22,6 +22,7 @@ import java.util.Map; parcelable CompatibilityChangeConfig; parcelable CompatibilityOverrideConfig; +parcelable CompatibilityOverridesToRemoveConfig; parcelable CompatibilityChangeInfo; /** * Platform private API for talking with the PlatformCompat service. @@ -204,6 +205,27 @@ interface IPlatformCompat { void clearOverrideForTest(long changeId, String packageName); /** + * Restores the default behaviour for compatibility changes on release builds. + * + * <p>The caller to this API needs to hold + * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids + * in {@code overridesToRemove} need to annotated with + * {@link android.compat.annotation.Overridable}. + * + * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to + * be {@code false}. + * + * <p>Note that this does not kill the app, and therefore overrides read from the app process + * will not be updated. Overrides read from the system process do take effect. + * + * @param overridesToRemove parcelable containing the compat change overrides to be removed + * @param packageName the package name of the app whose changes will be restored to the + * default behaviour + * @throws SecurityException if overriding changes is not permitted + */ + void removeOverridesOnReleaseBuilds(in CompatibilityOverridesToRemoveConfig overridesToRemove, in String packageName); + + /** * Enables all compatibility changes that have enabledSinceTargetSdk == * {@param targetSdkVersion} for an app, subject to the policy. * diff --git a/core/java/com/android/internal/graphics/OWNERS b/core/java/com/android/internal/graphics/OWNERS new file mode 100644 index 000000000000..5851cbbdf33c --- /dev/null +++ b/core/java/com/android/internal/graphics/OWNERS @@ -0,0 +1 @@ +include /graphics/java/android/graphics/OWNERS
\ No newline at end of file diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 0fb2728aed73..dbba469dda1a 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -54,6 +54,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 1000; public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true; + public static final boolean DEFAULT_COLLECT_LATENCY_DATA = false; public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 1500; private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; @@ -89,19 +90,27 @@ public class BinderCallsStats implements BinderInternal.Observer { private boolean mAddDebugEntries = false; private boolean mTrackDirectCallingUid = DEFAULT_TRACK_DIRECT_CALLING_UID; private boolean mTrackScreenInteractive = DEFAULT_TRACK_SCREEN_INTERACTIVE; + private boolean mCollectLatencyData = DEFAULT_COLLECT_LATENCY_DATA; private CachedDeviceState.Readonly mDeviceState; private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch; + private BinderLatencyObserver mLatencyObserver; + /** Injector for {@link BinderCallsStats}. */ public static class Injector { public Random getRandomGenerator() { return new Random(); } + + public BinderLatencyObserver getLatencyObserver() { + return new BinderLatencyObserver(new BinderLatencyObserver.Injector()); + } } public BinderCallsStats(Injector injector) { this.mRandom = injector.getRandomGenerator(); + this.mLatencyObserver = injector.getLatencyObserver(); } public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) { @@ -128,7 +137,10 @@ public class BinderCallsStats implements BinderInternal.Observer { if (shouldRecordDetailedData()) { s.cpuTimeStarted = getThreadTimeMicro(); s.timeStarted = getElapsedRealtimeMicro(); + } else if (mCollectLatencyData) { + s.timeStarted = getElapsedRealtimeMicro(); } + return s; } @@ -153,6 +165,10 @@ public class BinderCallsStats implements BinderInternal.Observer { private void processCallEnded(CallSession s, int parcelRequestSize, int parcelReplySize, int workSourceUid) { + if (mCollectLatencyData) { + mLatencyObserver.callEnded(s); + } + // Non-negative time signals we need to record data for this call. final boolean recordCall = s.cpuTimeStarted >= 0; final long duration; @@ -555,6 +571,17 @@ public class BinderCallsStats implements BinderInternal.Observer { } } + /** Whether to collect latency histograms. */ + public void setCollectLatencyData(boolean collectLatencyData) { + mCollectLatencyData = collectLatencyData; + } + + /** Whether to collect latency histograms. */ + @VisibleForTesting + public boolean getCollectLatencyData() { + return mCollectLatencyData; + } + public void reset() { synchronized (mLock) { mCallStatsCount = 0; @@ -565,6 +592,8 @@ public class BinderCallsStats implements BinderInternal.Observer { if (mBatteryStopwatch != null) { mBatteryStopwatch.reset(); } + // Do not reset the latency observer as binder stats and latency will be pushed to + // statsd at different intervals so the resets should not be coupled. } } @@ -767,6 +796,10 @@ public class BinderCallsStats implements BinderInternal.Observer { return mExceptionCounts; } + public BinderLatencyObserver getLatencyObserver() { + return mLatencyObserver; + } + @VisibleForTesting public static <T> List<T> getHighestValues(List<T> list, ToDoubleFunction<T> toDouble, double percentile) { diff --git a/core/java/com/android/internal/os/BinderLatencyBuckets.java b/core/java/com/android/internal/os/BinderLatencyBuckets.java new file mode 100644 index 000000000000..d7d2d6a8f9dd --- /dev/null +++ b/core/java/com/android/internal/os/BinderLatencyBuckets.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Arrays; + +/** + * Generates the bucket thresholds (with a custom logarithmic scale) for a histogram to store + * latency samples in. + */ +public class BinderLatencyBuckets { + private static final String TAG = "BinderLatencyBuckets"; + private final int[] mBuckets; + + /** + * @param bucketCount the number of buckets the histogram should have + * @param firstBucketSize the size of the first bucket (used to avoid excessive small buckets) + * @param scaleFactor the rate in which each consecutive bucket increases (before rounding) + */ + public BinderLatencyBuckets(int bucketCount, int firstBucketSize, float scaleFactor) { + int[] buffer = new int[bucketCount - 1]; + buffer[0] = firstBucketSize; + + // Last value and the target are disjoint as we never want to create buckets smaller than 1. + double lastTarget = firstBucketSize; + + // First bucket is already created and the last bucket is anything greater than the final + // bucket in the list, so create 'bucketCount' - 2 buckets. + for (int i = 1; i < bucketCount - 1; i++) { + // Increase the target bucket limit value by the scale factor. + double nextTarget = lastTarget * scaleFactor; + + if (nextTarget > Integer.MAX_VALUE) { + // Do not throw an exception here as this should not affect binder calls. + Slog.w(TAG, "Attempted to create a bucket larger than maxint"); + mBuckets = Arrays.copyOfRange(buffer, 0, i); + return; + } + + if ((int) nextTarget > buffer[i - 1]) { + // Convert the target bucket limit value to an integer. + buffer[i] = (int) nextTarget; + } else { + // Avoid creating redundant buckets, so bucket size should be 1 at a minimum. + buffer[i] = buffer[i - 1] + 1; + } + lastTarget = nextTarget; + } + mBuckets = buffer; + } + + /** Gets the bucket index to insert the provided sample in. */ + public int sampleToBucket(int sample) { + if (sample >= mBuckets[mBuckets.length - 1]) { + return mBuckets.length; + } + + // Binary search returns the element index if it is contained in the list - in this case the + // correct bucket is the index after as we use [minValue, maxValue) for bucket boundaries. + // Otherwise, it returns (-(insertion point) - 1), where insertion point is the point where + // to insert the element so that the array remains sorted - in this case the bucket index + // is the insertion point. + int searchResult = Arrays.binarySearch(mBuckets, sample); + return searchResult < 0 ? -(1 + searchResult) : searchResult + 1; + } + + @VisibleForTesting + public int[] getBuckets() { + return mBuckets; + } +} diff --git a/core/java/com/android/internal/os/BinderLatencyObserver.java b/core/java/com/android/internal/os/BinderLatencyObserver.java new file mode 100644 index 000000000000..59cc66d79bce --- /dev/null +++ b/core/java/com/android/internal/os/BinderLatencyObserver.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.annotation.Nullable; +import android.os.Binder; +import android.os.SystemClock; +import android.util.ArrayMap; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BinderInternal.CallSession; + +import java.util.Random; + +/** Collects statistics about Binder call latency per calling API and method. */ +public class BinderLatencyObserver { + private static final String TAG = "BinderLatencyObserver"; + public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 10; + + // Histogram buckets parameters. + public static final int BUCKET_COUNT_DEFAULT = 100; + public static final int FIRST_BUCKET_SIZE_DEFAULT = 5; + public static final float BUCKET_SCALE_FACTOR_DEFAULT = 1.125f; + + @GuardedBy("mLock") + private final ArrayMap<LatencyDims, int[]> mLatencyHistograms = new ArrayMap<>(); + private final Object mLock = new Object(); + + // Sampling period to control how often to track CPU usage. 1 means all calls, 100 means ~1 out + // of 100 requests. + private int mPeriodicSamplingInterval = PERIODIC_SAMPLING_INTERVAL_DEFAULT; + + private int mBucketCount = BUCKET_COUNT_DEFAULT; + private int mFirstBucketSize = FIRST_BUCKET_SIZE_DEFAULT; + private float mBucketScaleFactor = BUCKET_SCALE_FACTOR_DEFAULT; + + private final Random mRandom; + private BinderLatencyBuckets mLatencyBuckets; + + /** Injector for {@link BinderLatencyObserver}. */ + public static class Injector { + public Random getRandomGenerator() { + return new Random(); + } + } + + public BinderLatencyObserver(Injector injector) { + mRandom = injector.getRandomGenerator(); + mLatencyBuckets = new BinderLatencyBuckets( + mBucketCount, mFirstBucketSize, mBucketScaleFactor); + } + + /** Should be called when a Binder call completes, will store latency data. */ + public void callEnded(@Nullable CallSession s) { + if (s == null || s.exceptionThrown || !shouldKeepSample()) { + return; + } + + LatencyDims dims = new LatencyDims(s.binderClass, s.transactionCode); + long callDuration = getElapsedRealtimeMicro() - s.timeStarted; + + // Find the bucket this sample should go to. + int bucketIdx = mLatencyBuckets.sampleToBucket( + callDuration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) callDuration); + + synchronized (mLock) { + int[] buckets = mLatencyHistograms.get(dims); + if (buckets == null) { + buckets = new int[mBucketCount]; + mLatencyHistograms.put(dims, buckets); + } + + // Increment the correct bucket. + if (buckets[bucketIdx] < Integer.MAX_VALUE) { + buckets[bucketIdx] += 1; + } + } + } + + protected long getElapsedRealtimeMicro() { + return SystemClock.elapsedRealtimeNanos() / 1000; + } + + protected boolean shouldKeepSample() { + return mRandom.nextInt() % mPeriodicSamplingInterval == 0; + } + + /** Updates the sampling interval. */ + public void setSamplingInterval(int samplingInterval) { + if (samplingInterval <= 0) { + Slog.w(TAG, "Ignored invalid sampling interval (value must be positive): " + + samplingInterval); + return; + } + + synchronized (mLock) { + if (samplingInterval != mPeriodicSamplingInterval) { + mPeriodicSamplingInterval = samplingInterval; + reset(); + } + } + } + + /** Updates the histogram buckets parameters. */ + public void setHistogramBucketsParams( + int bucketCount, int firstBucketSize, float bucketScaleFactor) { + synchronized (mLock) { + if (bucketCount != mBucketCount || firstBucketSize != mFirstBucketSize + || bucketScaleFactor != mBucketScaleFactor) { + mBucketCount = bucketCount; + mFirstBucketSize = firstBucketSize; + mBucketScaleFactor = bucketScaleFactor; + mLatencyBuckets = new BinderLatencyBuckets( + mBucketCount, mFirstBucketSize, mBucketScaleFactor); + reset(); + } + } + } + + /** Resets the sample collection. */ + public void reset() { + synchronized (mLock) { + mLatencyHistograms.clear(); + } + } + + /** Container for binder latency information. */ + public static class LatencyDims { + // Binder interface descriptor. + private Class<? extends Binder> mBinderClass; + // Binder transaction code. + private int mTransactionCode; + // Cached hash code, 0 if not set yet. + private int mHashCode = 0; + + public LatencyDims(Class<? extends Binder> binderClass, int transactionCode) { + this.mBinderClass = binderClass; + this.mTransactionCode = transactionCode; + } + + public Class<? extends Binder> getBinderClass() { + return mBinderClass; + } + + public int getTransactionCode() { + return mTransactionCode; + } + + @Override + public boolean equals(final Object other) { + if (other == null || !(other instanceof LatencyDims)) { + return false; + } + LatencyDims o = (LatencyDims) other; + return mTransactionCode == o.getTransactionCode() && mBinderClass == o.getBinderClass(); + } + + @Override + public int hashCode() { + if (mHashCode != 0) { + return mHashCode; + } + int hash = mTransactionCode; + hash = 31 * hash + mBinderClass.hashCode(); + mHashCode = hash; + return hash; + } + } + + @VisibleForTesting + public ArrayMap<LatencyDims, int[]> getLatencyHistograms() { + return mLatencyHistograms; + } +} diff --git a/core/java/com/android/internal/util/StringPool.java b/core/java/com/android/internal/util/StringPool.java new file mode 100644 index 000000000000..c5180a3fe8cf --- /dev/null +++ b/core/java/com/android/internal/util/StringPool.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +/** + * A pool of string instances. Unlike the {@link String#intern() VM's + * interned strings}, this pool provides no guarantee of reference equality. + * It is intended only to save allocations. This class is not thread safe. + * + * @hide + */ +public final class StringPool { + + private final String[] mPool = new String[512]; + + /** + * Constructs string pool. + */ + public StringPool() { + } + + private static boolean contentEquals(String s, char[] chars, int start, int length) { + if (s.length() != length) { + return false; + } + for (int i = 0; i < length; i++) { + if (chars[start + i] != s.charAt(i)) { + return false; + } + } + return true; + } + + /** + * Returns a string equal to {@code new String(array, start, length)}. + * + * @param array buffer containing string chars + * @param start offset in {@code array} where string starts + * @param length length of string + * @return string equal to {@code new String(array, start, length)} + */ + public String get(char[] array, int start, int length) { + // Compute an arbitrary hash of the content + int hashCode = 0; + for (int i = start; i < start + length; i++) { + hashCode = (hashCode * 31) + array[i]; + } + + // Pick a bucket using Doug Lea's supplemental secondaryHash function (from HashMap) + hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12); + hashCode ^= (hashCode >>> 7) ^ (hashCode >>> 4); + int index = hashCode & (mPool.length - 1); + + String pooled = mPool[index]; + if (pooled != null && contentEquals(pooled, array, start, length)) { + return pooled; + } + + String result = new String(array, start, length); + mPool[index] = result; + return result; + } +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index afd19b63bc71..382acc062d62 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -149,7 +149,6 @@ cc_library_shared { "android_os_VintfRuntimeInfo.cpp", "android_os_incremental_IncrementalManager.cpp", "android_net_LocalSocketImpl.cpp", - "android_net_NetworkUtils.cpp", "android_service_DataLoaderService.cpp", "android_util_AssetManager.cpp", "android_util_Binder.cpp", @@ -216,6 +215,7 @@ cc_library_shared { static_libs: [ "libasync_safe", + "libconnectivityframeworkutils", "libbinderthreadstateutils", "libdmabufinfo", "libgif", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 855448b21069..114f3955fc86 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -630,6 +630,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX]; char saveResolvedClassesDelayMsOptsBuf[ sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX]; + char profileMinSavePeriodOptsBuf[sizeof("-Xps-min-save-period-ms:")-1 + PROPERTY_VALUE_MAX]; char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX]; char madviseWillNeedFileSizeVdex[ sizeof("-XMadviseWillNeedVdexFileSize:")-1 + PROPERTY_VALUE_MAX]; @@ -662,6 +663,8 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p char extraOptsBuf[PROPERTY_VALUE_MAX]; char voldDecryptBuf[PROPERTY_VALUE_MAX]; char perfettoHprofOptBuf[sizeof("-XX:PerfettoHprof=") + PROPERTY_VALUE_MAX]; + char perfettoJavaHeapStackOptBuf[ + sizeof("-XX:PerfettoJavaHeapStackProf=") + PROPERTY_VALUE_MAX]; enum { kEMDefault, kEMIntPortable, @@ -776,6 +779,10 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p parseRuntimeOption("dalvik.vm.perfetto_hprof", perfettoHprofOptBuf, "-XX:PerfettoHprof=", "true"); + // Enable PerfettoJavaHeapStackProf in the zygote + parseRuntimeOption("dalvik.vm.perfetto_javaheap", perfettoJavaHeapStackOptBuf, + "-XX:PerfettoJavaHeapStackProf=", "true"); + if (primary_zygote) { addOption("-Xprimaryzygote"); } @@ -859,6 +866,9 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p parseRuntimeOption("dalvik.vm.ps-resolved-classes-delay-ms", saveResolvedClassesDelayMsOptsBuf, "-Xps-save-resolved-classes-delay-ms:"); + parseRuntimeOption("dalvik.vm.ps-min-save-period-ms", profileMinSavePeriodOptsBuf, + "-Xps-min-save-period-ms:"); + property_get("ro.config.low_ram", propBuf, ""); if (strcmp(propBuf, "true") == 0) { addOption("-XX:LowMemoryMode"); diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h index b1b39f3e36ff..0e6b587db945 100644 --- a/core/jni/android_media_AudioFormat.h +++ b/core/jni/android_media_AudioFormat.h @@ -39,6 +39,14 @@ #define ENCODING_E_AC3_JOC 18 #define ENCODING_DOLBY_MAT 19 #define ENCODING_OPUS 20 +#define ENCODING_PCM_24BIT_PACKED 21 +#define ENCODING_PCM_32BIT 22 +#define ENCODING_MPEGH_BL_L3 23 +#define ENCODING_MPEGH_BL_L4 24 +#define ENCODING_MPEGH_LC_L3 25 +#define ENCODING_MPEGH_LC_L4 26 +#define ENCODING_DTS_UHD 27 +#define ENCODING_DRA 28 #define ENCODING_INVALID 0 #define ENCODING_DEFAULT 1 @@ -92,6 +100,22 @@ static inline audio_format_t audioFormatToNative(int audioFormat) return AUDIO_FORMAT_MAT; case ENCODING_OPUS: return AUDIO_FORMAT_OPUS; + case ENCODING_PCM_24BIT_PACKED: + return AUDIO_FORMAT_PCM_24_BIT_PACKED; + case ENCODING_PCM_32BIT: + return AUDIO_FORMAT_PCM_32_BIT; + case ENCODING_MPEGH_BL_L3: + return AUDIO_FORMAT_MPEGH_BL_L3; + case ENCODING_MPEGH_BL_L4: + return AUDIO_FORMAT_MPEGH_BL_L4; + case ENCODING_MPEGH_LC_L3: + return AUDIO_FORMAT_MPEGH_LC_L3; + case ENCODING_MPEGH_LC_L4: + return AUDIO_FORMAT_MPEGH_LC_L4; + case ENCODING_DTS_UHD: + return AUDIO_FORMAT_DTS_UHD; + case ENCODING_DRA: + return AUDIO_FORMAT_DRA; default: return AUDIO_FORMAT_INVALID; } @@ -107,10 +131,15 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat) case AUDIO_FORMAT_PCM_FLOAT: return ENCODING_PCM_FLOAT; - // map these to ENCODING_PCM_FLOAT - case AUDIO_FORMAT_PCM_8_24_BIT: + // As of S, these extend integer precision formats now return more specific values + // than ENCODING_PCM_FLOAT. case AUDIO_FORMAT_PCM_24_BIT_PACKED: + return ENCODING_PCM_24BIT_PACKED; case AUDIO_FORMAT_PCM_32_BIT: + return ENCODING_PCM_32BIT; + + // map this to ENCODING_PCM_FLOAT + case AUDIO_FORMAT_PCM_8_24_BIT: return ENCODING_PCM_FLOAT; case AUDIO_FORMAT_AC3: @@ -148,6 +177,18 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat) return ENCODING_DOLBY_MAT; case AUDIO_FORMAT_OPUS: return ENCODING_OPUS; + case AUDIO_FORMAT_MPEGH_BL_L3: + return ENCODING_MPEGH_BL_L3; + case AUDIO_FORMAT_MPEGH_BL_L4: + return ENCODING_MPEGH_BL_L4; + case AUDIO_FORMAT_MPEGH_LC_L3: + return ENCODING_MPEGH_LC_L3; + case AUDIO_FORMAT_MPEGH_LC_L4: + return ENCODING_MPEGH_LC_L4; + case AUDIO_FORMAT_DTS_UHD: + return ENCODING_DTS_UHD; + case AUDIO_FORMAT_DRA: + return ENCODING_DRA; case AUDIO_FORMAT_DEFAULT: return ENCODING_DEFAULT; default: diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index feb8930a0dbf..1a7f6e8863ff 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2273,10 +2273,19 @@ android_media_AudioSystem_setSurroundFormatEnabled(JNIEnv *env, jobject thiz, return (jint)nativeToJavaStatus(status); } -static jint android_media_AudioSystem_get_FCC_8(JNIEnv *env, jobject thiz) { +static jint android_media_AudioSystem_getMaxChannelCount(JNIEnv *env, jobject thiz) { return FCC_8; } +static jint android_media_AudioSystem_getMaxSampleRate(JNIEnv *env, jobject thiz) { + // see frameworks/av/services/audiopolicy/common/include/policy.h + return 192000; // SAMPLE_RATE_HZ_MAX (for API) +} + +static jint android_media_AudioSystem_getMinSampleRate(JNIEnv *env, jobject thiz) { + return 4000; // SAMPLE_RATE_HZ_MIN (for API) +} + static jint android_media_AudioSystem_setAssistantUid(JNIEnv *env, jobject thiz, jint uid) { @@ -2672,14 +2681,18 @@ static const JNINativeMethod gEventHandlerMethods[] = { (void *)android_media_AudioSystem_eventHandlerFinalize}, }; -static const JNINativeMethod gGetFCC8Methods[] = { - {"native_get_FCC_8", "()I", (void *)android_media_AudioSystem_get_FCC_8}, +static const JNINativeMethod gFrameworkCapabilities[] = { + {"native_getMaxChannelCount", "()I", (void *)android_media_AudioSystem_getMaxChannelCount}, + {"native_getMaxSampleRate", "()I", (void *)android_media_AudioSystem_getMaxSampleRate}, + {"native_getMinSampleRate", "()I", (void *)android_media_AudioSystem_getMinSampleRate}, }; int register_android_media_AudioSystem(JNIEnv *env) { // This needs to be done before hooking up methods AudioTrackRoutingProxy (below) - RegisterMethodsOrDie(env, kClassPathName, gGetFCC8Methods, NELEM(gGetFCC8Methods)); + // as the calls are performed in the static initializer of AudioSystem. + RegisterMethodsOrDie(env, kClassPathName, gFrameworkCapabilities, + NELEM(gFrameworkCapabilities)); jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index 4bd33a9cbd3b..1baea2aecc3c 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -37,11 +37,13 @@ static jmethodID gLongValueOf; namespace android { +using vintf::CompatibilityMatrix; using vintf::HalManifest; using vintf::Level; using vintf::SchemaType; using vintf::to_string; using vintf::toXml; +using vintf::Version; using vintf::VintfObject; using vintf::Vndk; @@ -119,6 +121,28 @@ static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) { return env->NewStringUTF(cString.c_str()); } +static jstring android_os_VintfObject_getPlatformSepolicyVersion(JNIEnv* env, jclass) { + std::shared_ptr<const CompatibilityMatrix> matrix = + VintfObject::GetFrameworkCompatibilityMatrix(); + if (matrix == nullptr || matrix->type() != SchemaType::FRAMEWORK) { + jniThrowRuntimeException(env, "Cannot get framework compatibility matrix"); + return nullptr; + } + + auto versions = matrix->getSepolicyVersions(); + if (versions.empty()) { + jniThrowRuntimeException(env, + "sepolicy_version in framework compatibility matrix is empty"); + return nullptr; + } + + Version latest; + for (const auto& range : versions) { + latest = std::max(latest, range.maxVer()); + } + return env->NewStringUTF(to_string(latest).c_str()); +} + static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) { std::shared_ptr<const HalManifest> manifest = VintfObject::GetFrameworkHalManifest(); if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) { @@ -145,12 +169,17 @@ static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersi // ---------------------------------------------------------------------------- static const JNINativeMethod gVintfObjectMethods[] = { - {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report}, - {"verifyWithoutAvb", "()I", (void*)android_os_VintfObject_verifyWithoutAvb}, - {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions}, - {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion}, - {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots}, - {"getTargetFrameworkCompatibilityMatrixVersion", "()Ljava/lang/Long;", (void*)android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion}, + {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report}, + {"verifyWithoutAvb", "()I", (void*)android_os_VintfObject_verifyWithoutAvb}, + {"getHalNamesAndVersions", "()[Ljava/lang/String;", + (void*)android_os_VintfObject_getHalNamesAndVersions}, + {"getSepolicyVersion", "()Ljava/lang/String;", + (void*)android_os_VintfObject_getSepolicyVersion}, + {"getPlatformSepolicyVersion", "()Ljava/lang/String;", + (void*)android_os_VintfObject_getPlatformSepolicyVersion}, + {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots}, + {"getTargetFrameworkCompatibilityMatrixVersion", "()Ljava/lang/Long;", + (void*)android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion}, }; const char* const kVintfObjectPathName = "android/os/VintfObject"; diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp index 24fef4881e4c..5fe96ede202e 100644 --- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp +++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp @@ -402,7 +402,7 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( socklen_t cred_size = sizeof credentials; if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1 || cred_size != sizeof credentials) { - fail_fn_1("ForkMany failed to get initial credentials, %s", strerror(errno)); + fail_fn_1(CREATE_ERROR("ForkMany failed to get initial credentials, %s", strerror(errno))); } bool first_time = true; @@ -453,7 +453,7 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( close(session_socket); int new_fd = accept(zygote_socket_fd, nullptr, nullptr); if (new_fd == -1) { - fail_fn_z("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno)); + fail_fn_z(CREATE_ERROR("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno))); } if (new_fd != session_socket) { // Move new_fd back to the old value, so that we don't have to change Java-level data diff --git a/core/jni/include/android_runtime/AndroidRuntime.h b/core/jni/include/android_runtime/AndroidRuntime.h index d86d9340e667..bf2ba772c39d 100644 --- a/core/jni/include/android_runtime/AndroidRuntime.h +++ b/core/jni/include/android_runtime/AndroidRuntime.h @@ -19,7 +19,6 @@ #ifndef _RUNTIME_ANDROID_RUNTIME_H #define _RUNTIME_ANDROID_RUNTIME_H -#include <binder/IBinder.h> #include <jni.h> #include <pthread.h> #include <utils/Errors.h> diff --git a/core/proto/android/providers/OWNERS b/core/proto/android/providers/OWNERS new file mode 100644 index 000000000000..1f5cd9a5c3b8 --- /dev/null +++ b/core/proto/android/providers/OWNERS @@ -0,0 +1 @@ +include /packages/SettingsProvider/OWNERS diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index cc4e2bb59787..4a57448ed668 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -398,6 +398,8 @@ <protected-broadcast android:name="android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED" /> <protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" /> <protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" /> + <!-- This broadcast is no longer sent in S but it should stay protected to avoid third party + apps broadcasting this and confusing old system apps that may not have been updated. --> <protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" /> <protected-broadcast android:name="android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED" /> @@ -3792,6 +3794,13 @@ <permission android:name="com.android.permission.USE_INSTALLER_V2" android:protectionLevel="signature|verifier" /> + <!-- @TestApi Allows a testOnly application to get installed. + <p>Not for use by third-party applications. + @hide + --> + <permission android:name="android.permission.INSTALL_TEST_ONLY_PACKAGE" + android:protectionLevel="signature" /> + <!-- @SystemApi @TestApi Allows an application to clear user data. <p>Not for use by third-party applications @hide diff --git a/core/res/OWNERS b/core/res/OWNERS index 9d739b90bcc5..7a8da36d8a7d 100644 --- a/core/res/OWNERS +++ b/core/res/OWNERS @@ -1,6 +1,7 @@ adamp@google.com alanv@google.com asc@google.com +cinek@google.com dsandler@android.com dsandler@google.com dupin@google.com @@ -8,6 +9,7 @@ hackbod@android.com hackbod@google.com ilyamaty@google.com jaggies@google.com +jdemeulenaere@google.com jsharkey@android.com jsharkey@google.com juliacr@google.com @@ -17,7 +19,9 @@ nandana@google.com narayan@google.com ogunwale@google.com patb@google.com +shanh@google.com svetoslavganov@android.com svetoslavganov@google.com toddke@google.com +tsuji@google.com yamasani@google.com diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index cbc08ba621a9..6bdfe289112c 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -632,6 +632,13 @@ <!-- The default minimal size of a PiP task, in both dimensions. --> <dimen name="default_minimal_size_pip_resizable_task">108dp</dimen> + <!-- + The overridable minimal size of a PiP task, in both dimensions. + Different from default_minimal_size_pip_resizable_task, this is to limit the dimension + when the pinned stack size is overridden by app via minWidth/minHeight. + --> + <dimen name="overridable_minimal_size_pip_resizable_task">48dp</dimen> + <!-- Height of a task when in minimized mode from the top when launcher is resizable. --> <dimen name="task_height_of_minimized_mode">80dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c06e7ded81f8..43f4300e04eb 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1941,6 +1941,7 @@ <java-symbol type="fraction" name="config_dimBehindFadeDuration" /> <java-symbol type="dimen" name="default_minimal_size_resizable_task" /> <java-symbol type="dimen" name="default_minimal_size_pip_resizable_task" /> + <java-symbol type="dimen" name="overridable_minimal_size_pip_resizable_task" /> <java-symbol type="dimen" name="task_height_of_minimized_mode" /> <java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" /> <java-symbol type="bool" name="config_allowPriorityVibrationsInLowPowerMode" /> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index d5733e34a8ef..2650d9f69dd7 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -40,7 +40,7 @@ <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" /> <!-- Argentina: 5 digits, known short codes listed --> - <shortcode country="ar" pattern="\\d{5}" free="11711|28291" /> + <shortcode country="ar" pattern="\\d{5}" free="11711|28291|44077" /> <!-- Armenia: 3-4 digits, emergency numbers 10[123] --> <shortcode country="am" pattern="\\d{3,4}" premium="11[2456]1|3024" free="10[123]" /> @@ -76,14 +76,14 @@ <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765|30075|30047" /> <!-- Chile: 4-5 digits (not confirmed), known premium codes listed --> - <shortcode country="cl" pattern="\\d{4,5}" free="9963|9240" /> + <shortcode country="cl" pattern="\\d{4,5}" free="9963|9240|1038" /> <!-- China: premium shortcodes start with "1066", free shortcodes start with "1065": http://clients.txtnation.com/entries/197192-china-premium-sms-short-code-requirements --> <shortcode country="cn" premium="1066.*" free="1065.*" /> <!-- Colombia: 1-6 digits (not confirmed) --> - <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960" /> + <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739" /> <!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU --> <shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" /> @@ -156,7 +156,7 @@ <shortcode country="jp" pattern="\\d{1,5}" free="8083" /> <!-- Kenya: 5 digits, known premium codes listed --> - <shortcode country="ke" pattern="\\d{5}" free="21725" /> + <shortcode country="ke" pattern="\\d{5}" free="21725|21562|40520" /> <!-- Kyrgyzstan: 4 digits, known premium codes listed --> <shortcode country="kg" pattern="\\d{4}" premium="415[2367]|444[69]" /> @@ -187,13 +187,13 @@ <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963" /> <!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf --> - <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" /> + <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" /> <!-- The Netherlands, 4 digits, known premium codes listed, plus EU --> <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" /> <!-- Nigeria --> - <shortcode country="ng" pattern="\\d{1,5}" free="2441" /> + <shortcode country="ng" pattern="\\d{1,5}" free="2441|55019" /> <!-- Norway: 4-5 digits (not confirmed), known premium codes listed --> <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" /> @@ -202,7 +202,7 @@ <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|176|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" /> <!-- Peru: 4-5 digits (not confirmed), known premium codes listed --> - <shortcode country="pe" pattern="\\d{4,5}" free="9963" /> + <shortcode country="pe" pattern="\\d{4,5}" free="9963|40777" /> <!-- Philippines --> <shortcode country="ph" pattern="\\d{1,5}" free="2147|5495|5496" /> @@ -224,7 +224,7 @@ <shortcode country="re" pattern="\\d{1,5}" free="38600,36300,36303,959" /> <!-- Romania: 4 digits, plus EU: http://www.simplus.ro/en/resources/glossary-of-terms/ --> - <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}|3654|8360" /> + <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}|3654|8360|3838" /> <!-- Russia: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-russia/ --> <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" free="6954|8501" standard="2037|2044"/> @@ -252,7 +252,7 @@ <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" /> <!-- Turkey --> - <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493" /> + <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493|3193" /> <!-- Ukraine: 4 digits, known premium codes listed --> <shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" /> @@ -268,6 +268,6 @@ <shortcode country="yt" pattern="\\d{1,5}" free="38600,36300,36303,959" /> <!-- South Africa --> - <shortcode country="za" pattern="\d{1,5}" free="44136" /> + <shortcode country="za" pattern="\d{1,5}" free="44136|30791|36056" /> </shortcodes> diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java index dd60dd4c40f9..1a636604ed57 100644 --- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java +++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java @@ -44,8 +44,6 @@ import com.android.bandwidthtest.NetworkState; import com.android.bandwidthtest.NetworkState.StateTransitionDirection; import com.android.internal.util.AsyncChannel; -import junit.framework.Assert; - import java.io.IOException; import java.net.UnknownHostException; import java.util.List; @@ -76,7 +74,11 @@ public class ConnectionUtil { private WifiManager mWifiManager; private Context mContext; // Verify connectivity state - private static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1; + // ConnectivityManager.TYPE_* is deprecated and no longer extended, so use the max public + // network type - TYPE_VPN should be enough. + // TODO: Replace registering CONNECTIVITY_ACTION with registering NetworkCallback and check + // network by NetworkCapabilities.TRANSPORT_* and NetworkCapabilities.hasTransport() instead. + private static final int NUM_NETWORK_TYPES = ConnectivityManager.TYPE_VPN + 1; private NetworkState[] mConnectivityState = new NetworkState[NUM_NETWORK_TYPES]; public ConnectionUtil(Context context) { diff --git a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java index 3ebe1039d975..02998325708b 100644 --- a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java +++ b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java @@ -91,7 +91,7 @@ public class NetworkStatsBenchmark { public void timeMigrateTun(int reps) { for (int i = 0; i < reps; i++) { NetworkStats stats = mNetworkStats.clone(); - stats.migrateTun(TUN_UID, TUN_IFACE, getVpnUnderlyingIfaces()); + stats.migrateTun(TUN_UID, TUN_IFACE, Arrays.asList(getVpnUnderlyingIfaces())); } } diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index eb9c7b66d642..cec62164e57a 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -753,6 +753,34 @@ public class BinderCallsStatsTest { assertEquals(1, callStats.recordedCallCount); } + @Test + public void testLatencyCollectionEnabled() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setCollectLatencyData(true); + + Binder binder = new Binder(); + CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.time += 10; + bcs.elapsedTime += 20; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + assertEquals(1, bcs.getLatencyObserver().getLatencyHistograms().size()); + } + + @Test + public void testLatencyCollectionDisabledByDefault() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + assertEquals(false, bcs.getCollectLatencyData()); + + Binder binder = new Binder(); + CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.time += 10; + bcs.elapsedTime += 20; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + assertEquals(0, bcs.getLatencyObserver().getLatencyHistograms().size()); + } + class TestBinderCallsStats extends BinderCallsStats { public int callingUid = CALLING_UID; public long time = 1234; @@ -774,6 +802,10 @@ public class BinderCallsStatsTest { } }; } + + public BinderLatencyObserver getLatencyObserver() { + return new BinderLatencyObserverTest.TestBinderLatencyObserver(); + } }); setSamplingInterval(1); setAddDebugEntries(false); diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyBucketsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyBucketsTest.java new file mode 100644 index 000000000000..b2054f1ee9ad --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyBucketsTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +@Presubmit +public class BinderLatencyBucketsTest { + @Test + public void testBucketThresholds() { + BinderLatencyBuckets latencyBuckets = new BinderLatencyBuckets(10, 2, 1.45f); + assertThat(latencyBuckets.getBuckets()) + .asList() + .containsExactly(2, 3, 4, 6, 8, 12, 18, 26, 39) + .inOrder(); + } + + @Test + public void testSampleAssignment() { + BinderLatencyBuckets latencyBuckets = new BinderLatencyBuckets(10, 2, 1.45f); + assertEquals(0, latencyBuckets.sampleToBucket(0)); + assertEquals(0, latencyBuckets.sampleToBucket(1)); + assertEquals(1, latencyBuckets.sampleToBucket(2)); + assertEquals(2, latencyBuckets.sampleToBucket(3)); + assertEquals(3, latencyBuckets.sampleToBucket(4)); + assertEquals(5, latencyBuckets.sampleToBucket(9)); + assertEquals(6, latencyBuckets.sampleToBucket(13)); + assertEquals(7, latencyBuckets.sampleToBucket(25)); + assertEquals(9, latencyBuckets.sampleToBucket(100)); + } + + @Test + public void testMaxIntBuckets() { + BinderLatencyBuckets latencyBuckets = new BinderLatencyBuckets(5, Integer.MAX_VALUE / 2, 2); + assertThat(latencyBuckets.getBuckets()) + .asList() + .containsExactly(Integer.MAX_VALUE / 2, Integer.MAX_VALUE - 1) + .inOrder(); + + assertEquals(0, latencyBuckets.sampleToBucket(0)); + assertEquals(0, latencyBuckets.sampleToBucket(Integer.MAX_VALUE / 2 - 1)); + assertEquals(1, latencyBuckets.sampleToBucket(Integer.MAX_VALUE - 2)); + assertEquals(2, latencyBuckets.sampleToBucket(Integer.MAX_VALUE)); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java new file mode 100644 index 000000000000..f65fb9583d6c --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; + +import android.os.Binder; +import android.platform.test.annotations.Presubmit; +import android.util.ArrayMap; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.os.BinderInternal.CallSession; +import com.android.internal.os.BinderLatencyObserver.LatencyDims; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.Random; + +@SmallTest +@RunWith(AndroidJUnit4.class) +@Presubmit +public class BinderLatencyObserverTest { + @Test + public void testLatencyCollectionWithMultipleClasses() { + TestBinderLatencyObserver blo = new TestBinderLatencyObserver(); + blo.setHistogramBucketsParams(5, 5, 1.125f); + + Binder binder = new Binder(); + CallSession callSession = new CallSession(); + callSession.binderClass = binder.getClass(); + callSession.transactionCode = 1; + blo.callEnded(callSession); + blo.callEnded(callSession); + blo.callEnded(callSession); + callSession.transactionCode = 2; + blo.callEnded(callSession); + blo.callEnded(callSession); + + ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms(); + assertEquals(2, latencyHistograms.keySet().size()); + assertThat(latencyHistograms.get(new LatencyDims(binder.getClass(), 1))) + .asList().containsExactly(2, 0, 1, 0, 0).inOrder(); + assertThat(latencyHistograms.get(new LatencyDims(binder.getClass(), 2))) + .asList().containsExactly(0, 0, 0, 0, 2).inOrder(); + } + + @Test + public void testSampling() { + TestBinderLatencyObserver blo = new TestBinderLatencyObserver(); + blo.setSamplingInterval(2); + blo.setHistogramBucketsParams(5, 5, 1.125f); + + Binder binder = new Binder(); + CallSession callSession = new CallSession(); + callSession.binderClass = binder.getClass(); + callSession.transactionCode = 1; + blo.callEnded(callSession); + callSession.transactionCode = 2; + blo.callEnded(callSession); + + ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms(); + assertEquals(1, latencyHistograms.size()); + LatencyDims dims = latencyHistograms.keySet().iterator().next(); + assertEquals(binder.getClass(), dims.getBinderClass()); + assertEquals(1, dims.getTransactionCode()); + assertThat(latencyHistograms.get(dims)).asList().containsExactly(1, 0, 0, 0, 0).inOrder(); + } + + @Test + public void testTooCallLengthOverflow() { + TestBinderLatencyObserver blo = new TestBinderLatencyObserver(); + blo.setElapsedTime(2L + (long) Integer.MAX_VALUE); + blo.setHistogramBucketsParams(5, 5, 1.125f); + + Binder binder = new Binder(); + CallSession callSession = new CallSession(); + callSession.binderClass = binder.getClass(); + callSession.transactionCode = 1; + blo.callEnded(callSession); + + // The long call should be capped to maxint (to not overflow) and placed in the last bucket. + assertThat(blo.getLatencyHistograms() + .get(new LatencyDims(binder.getClass(), 1))) + .asList().containsExactly(0, 0, 0, 0, 1) + .inOrder(); + } + + @Test + public void testHistogramBucketOverflow() { + TestBinderLatencyObserver blo = new TestBinderLatencyObserver(); + blo.setHistogramBucketsParams(3, 5, 1.125f); + + Binder binder = new Binder(); + CallSession callSession = new CallSession(); + callSession.binderClass = binder.getClass(); + callSession.transactionCode = 1; + blo.callEnded(callSession); + + LatencyDims dims = new LatencyDims(binder.getClass(), 1); + // Fill the buckets with maxint. + Arrays.fill(blo.getLatencyHistograms().get(dims), Integer.MAX_VALUE); + assertThat(blo.getLatencyHistograms().get(dims)) + .asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + // Try to add another sample. + blo.callEnded(callSession); + // Make sure the buckets don't overflow. + assertThat(blo.getLatencyHistograms().get(dims)) + .asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + public static class TestBinderLatencyObserver extends BinderLatencyObserver { + private long mElapsedTime = 0; + + TestBinderLatencyObserver() { + // Make random generator not random. + super(new Injector() { + public Random getRandomGenerator() { + return new Random() { + int mCallCount = 0; + + public int nextInt() { + return mCallCount++; + } + }; + } + }); + setSamplingInterval(1); + } + + @Override + protected long getElapsedRealtimeMicro() { + mElapsedTime += 2; + return mElapsedTime; + } + + public void setElapsedTime(long time) { + mElapsedTime = time; + } + } +} diff --git a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java b/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java index 43f9b6feea45..48f4288d401e 100644 --- a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java +++ b/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java @@ -19,6 +19,7 @@ package android.nfc; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -62,7 +63,36 @@ public class NfcControllerAlwaysOnListenerTest { } @Test + public void testRegister_RegisterUnregisterWhenNotSupported() throws RemoteException { + // isControllerAlwaysOnSupported() returns false, not supported. + doReturn(false).when(mNfcAdapter).isControllerAlwaysOnSupported(); + NfcControllerAlwaysOnListener mListener = + new NfcControllerAlwaysOnListener(mNfcAdapter); + ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class); + ControllerAlwaysOnListener mockListener2 = mock(ControllerAlwaysOnListener.class); + + // Verify that the state listener will not registered with the NFC Adapter + mListener.register(getExecutor(), mockListener1); + verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any()); + + // Register a second client and no any call to NFC Adapter + mListener.register(getExecutor(), mockListener2); + verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any()); + + // Unregister first listener, and no any call to NFC Adapter + mListener.unregister(mockListener1); + verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any()); + verify(mNfcAdapter, times(0)).unregisterControllerAlwaysOnListener(any()); + + // Unregister second listener, and no any call to NFC Adapter + mListener.unregister(mockListener2); + verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any()); + verify(mNfcAdapter, times(0)).unregisterControllerAlwaysOnListener(any()); + } + + @Test public void testRegister_RegisterUnregister() throws RemoteException { + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); NfcControllerAlwaysOnListener mListener = new NfcControllerAlwaysOnListener(mNfcAdapter); ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class); @@ -89,6 +119,7 @@ public class NfcControllerAlwaysOnListenerTest { @Test public void testRegister_FirstRegisterFails() throws RemoteException { + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); NfcControllerAlwaysOnListener mListener = new NfcControllerAlwaysOnListener(mNfcAdapter); ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class); @@ -116,6 +147,7 @@ public class NfcControllerAlwaysOnListenerTest { @Test public void testRegister_RegisterSameListenerTwice() throws RemoteException { + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); NfcControllerAlwaysOnListener mListener = new NfcControllerAlwaysOnListener(mNfcAdapter); ControllerAlwaysOnListener mockListener = mock(ControllerAlwaysOnListener.class); @@ -132,7 +164,7 @@ public class NfcControllerAlwaysOnListenerTest { @Test public void testNotify_AllListenersNotified() throws RemoteException { - + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); NfcControllerAlwaysOnListener listener = new NfcControllerAlwaysOnListener(mNfcAdapter); List<ControllerAlwaysOnListener> mockListeners = new ArrayList<>(); for (int i = 0; i < 10; i++) { @@ -149,7 +181,8 @@ public class NfcControllerAlwaysOnListenerTest { } @Test - public void testStateChange_CorrectValue() { + public void testStateChange_CorrectValue() throws RemoteException { + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); runStateChangeValue(true, true); runStateChangeValue(false, false); diff --git a/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java b/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java new file mode 100644 index 000000000000..f67fd516fcf6 --- /dev/null +++ b/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +@SmallTest +public final class StringPoolTest extends AndroidTestCase { + + public void testStringPool() { + StringPool stringPool = new StringPool(); + String bcd = stringPool.get(new char[] { 'a', 'b', 'c', 'd', 'e' }, 1, 3); + assertEquals("bcd", bcd); + assertSame(bcd, stringPool.get(new char[] { 'a', 'b', 'c', 'd', 'e' }, 1, 3)); + } + + public void testHashCollision() { + StringPool stringPool = new StringPool(); + char[] a = { (char) 1, (char) 0 }; + char[] b = { (char) 0, (char) 31 }; + assertEquals(new String(a).hashCode(), new String(b).hashCode()); + + String aString = stringPool.get(a, 0, 2); + assertEquals(new String(a), aString); + String bString = stringPool.get(b, 0, 2); + assertEquals(new String(b), bString); + assertSame(bString, stringPool.get(b, 0, 2)); + assertNotSame(aString, stringPool.get(a, 0, 2)); + } +} diff --git a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java index bdaf63021503..4cad535a3a51 100644 --- a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java +++ b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java @@ -19,7 +19,6 @@ package android.uwb; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -114,30 +113,6 @@ public class AdapterStateListenerTest { } @Test - public void testRegister_FirstRegisterFails() throws RemoteException { - AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter); - AdapterStateCallback callback1 = mock(AdapterStateCallback.class); - AdapterStateCallback callback2 = mock(AdapterStateCallback.class); - - // Throw a remote exception whenever first registering - doThrow(mThrowRemoteException).when(mUwbAdapter).registerAdapterStateCallbacks(any()); - - adapterStateListener.register(getExecutor(), callback1); - verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any()); - - // No longer throw an exception, instead succeed - doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any()); - - // Register a different callback - adapterStateListener.register(getExecutor(), callback2); - verify(mUwbAdapter, times(2)).registerAdapterStateCallbacks(any()); - - // Ensure first callback was invoked again - verifyCallbackStateChangedInvoked(callback1, 2); - verifyCallbackStateChangedInvoked(callback2, 1); - } - - @Test public void testRegister_RegisterSameCallbackTwice() throws RemoteException { AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter); AdapterStateCallback callback = mock(AdapterStateCallback.class); @@ -162,13 +137,6 @@ public class AdapterStateListenerTest { runViaExecutor(); } - @Test - public void testCallback_RunViaExecutor_Failure() throws RemoteException { - // Verify that the callbacks are invoked on the executor when there is a remote exception - doThrow(mThrowRemoteException).when(mUwbAdapter).registerAdapterStateCallbacks(any()); - runViaExecutor(); - } - private void runViaExecutor() { AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter); AdapterStateCallback callback = mock(AdapterStateCallback.class); diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java index bd72d45297c1..00219e7f28ac 100644 --- a/keystore/java/android/security/Authorization.java +++ b/keystore/java/android/security/Authorization.java @@ -74,16 +74,19 @@ public class Authorization { * @param locked - whether it is a lock (true) or unlock (false) event * @param syntheticPassword - if it is an unlock event with the password, pass the synthetic * password provided by the LockSettingService + * @param unlockingSids - KeyMint secure user IDs that should be permitted to unlock + * UNLOCKED_DEVICE_REQUIRED keys. * * @return 0 if successful or a {@code ResponseCode}. */ public static int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId, - @Nullable byte[] syntheticPassword) { + @Nullable byte[] syntheticPassword, @Nullable long[] unlockingSids) { try { if (locked) { - getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null); + getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null, unlockingSids); } else { - getService().onLockScreenEvent(LockScreenEvent.UNLOCK, userId, syntheticPassword); + getService().onLockScreenEvent( + LockScreenEvent.UNLOCK, userId, syntheticPassword, unlockingSids); } return 0; } catch (RemoteException | NullPointerException e) { diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java index df579bba9dc2..1034847b761b 100644 --- a/keystore/java/android/security/KeyStore2.java +++ b/keystore/java/android/security/KeyStore2.java @@ -19,6 +19,7 @@ package android.security; import android.annotation.NonNull; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; +import android.os.Binder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; @@ -140,6 +141,7 @@ public class KeyStore2 { if (mBinder == null || retryLookup) { mBinder = IKeystoreService.Stub.asInterface(ServiceManager .getService(KEYSTORE2_SERVICE_NAME)); + Binder.allowBlocking(mBinder.asBinder()); } return mBinder; } diff --git a/keystore/java/android/security/KeyStoreOperation.java b/keystore/java/android/security/KeyStoreOperation.java index a6552dddc630..e6c1ea827118 100644 --- a/keystore/java/android/security/KeyStoreOperation.java +++ b/keystore/java/android/security/KeyStoreOperation.java @@ -18,6 +18,7 @@ package android.security; import android.annotation.NonNull; import android.hardware.security.keymint.KeyParameter; +import android.os.Binder; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.security.keymaster.KeymasterDefs; @@ -39,6 +40,7 @@ public class KeyStoreOperation { Long challenge, KeyParameter[] parameters ) { + Binder.allowBlocking(operation.asBinder()); this.mOperation = operation; this.mChallenge = challenge; this.mParameters = parameters; diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java index d188b6525579..b85dd742cc49 100644 --- a/keystore/java/android/security/KeyStoreSecurityLevel.java +++ b/keystore/java/android/security/KeyStoreSecurityLevel.java @@ -19,6 +19,7 @@ package android.security; import android.annotation.NonNull; import android.app.compat.CompatChanges; import android.hardware.security.keymint.KeyParameter; +import android.os.Binder; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.security.keystore.BackendBusyException; @@ -45,6 +46,7 @@ public class KeyStoreSecurityLevel { private final IKeystoreSecurityLevel mSecurityLevel; public KeyStoreSecurityLevel(IKeystoreSecurityLevel securityLevel) { + Binder.allowBlocking(securityLevel.asBinder()); this.mSecurityLevel = securityLevel; } diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java index be865a02a945..3980d3a0203b 100644 --- a/keystore/java/android/security/keystore/AttestationUtils.java +++ b/keystore/java/android/security/keystore/AttestationUtils.java @@ -293,6 +293,11 @@ public abstract class AttestationUtils { } catch (SecurityException e) { throw e; } catch (Exception e) { + // If a DeviceIdAttestationException was previously wrapped with some other type, + // let's throw the original exception instead of wrapping it yet again. + if (e.getCause() instanceof DeviceIdAttestationException) { + throw (DeviceIdAttestationException) e.getCause(); + } throw new DeviceIdAttestationException("Unable to perform attestation", e); } } diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java index 9d8a5effc2d7..e808c5cc51bd 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java @@ -579,7 +579,11 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { if (mCipher != null) { - return mCipher.doFinal(input, inputOffset, inputLen); + if (input == null && inputLen == 0) { + return mCipher.doFinal(); + } else { + return mCipher.doFinal(input, inputOffset, inputLen); + } } if (mCachedException != null) { diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java index fe05989c3846..97592b44ba2e 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java @@ -252,7 +252,9 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { blockModes, userAuthenticationRequired, (int) userAuthenticationValidityDurationSeconds, - keymasterHwEnforcedUserAuthenticators, + userAuthenticationRequirementEnforcedBySecureHardware + ? keymasterHwEnforcedUserAuthenticators + : keymasterSwEnforcedUserAuthenticators, userAuthenticationRequirementEnforcedBySecureHardware, userAuthenticationValidWhileOnBody, trustedUserPresenceRequired, diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java index 3e2fb94f0387..f3cfcf18dec1 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java @@ -41,6 +41,8 @@ import android.system.keystore2.KeyMetadata; import android.system.keystore2.ResponseCode; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -974,7 +976,6 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } private Set<String> getUniqueAliases() { - try { final KeyDescriptor[] keys = mKeyStore.list( getTargetDomain(), @@ -987,7 +988,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { return aliases; } catch (android.security.KeyStoreException e) { Log.e(TAG, "Failed to list keystore entries.", e); - return null; + return new HashSet<>(); } } @@ -1099,6 +1100,17 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { return caAlias; } + /** + * Used by Tests to initialize with a fake KeyStore2. + * @hide + * @param keystore + */ + @VisibleForTesting + public void initForTesting(KeyStore2 keystore) { + mKeyStore = keystore; + mNamespace = KeyProperties.NAMESPACE_APPLICATION; + } + @Override public void engineStore(OutputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException { diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp index 2315a8568c64..7de45233494b 100644 --- a/keystore/tests/Android.bp +++ b/keystore/tests/Android.bp @@ -28,6 +28,7 @@ android_test { static_libs: [ "androidx.test.rules", "hamcrest-library", + "mockito-target-minus-junit4", ], platform_apis: true, libs: ["android.test.runner"], diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java index b7d72fce6eba..2ae61ab3b38d 100644 --- a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java +++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java @@ -43,7 +43,6 @@ public final class ParcelableKeyGenParameterSpecTest { static final String ALIAS = "keystore-alias"; static final String ANOTHER_ALIAS = "another-keystore-alias"; static final int KEY_PURPOSES = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY; - static final int UID = 1230; static final int KEYSIZE = 2048; static final X500Principal SUBJECT = new X500Principal("CN=subject"); static final BigInteger SERIAL = new BigInteger("1234567890"); @@ -61,7 +60,7 @@ public final class ParcelableKeyGenParameterSpecTest { public static KeyGenParameterSpec configureDefaultSpec() { return new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES) - .setUid(UID) + .setNamespace(KeyProperties.NAMESPACE_WIFI) .setKeySize(KEYSIZE) .setCertificateSubject(SUBJECT) .setCertificateSerialNumber(SERIAL) @@ -88,10 +87,11 @@ public final class ParcelableKeyGenParameterSpecTest { .build(); } - public static void validateSpecValues(KeyGenParameterSpec spec, int uid, String alias) { + public static void validateSpecValues(KeyGenParameterSpec spec, + @KeyProperties.Namespace int namespace, String alias) { assertThat(spec.getKeystoreAlias(), is(alias)); assertThat(spec.getPurposes(), is(KEY_PURPOSES)); - assertThat(spec.getUid(), is(uid)); + assertThat(spec.getNamespace(), is(namespace)); assertThat(spec.getKeySize(), is(KEYSIZE)); assertThat(spec.getCertificateSubject(), is(SUBJECT)); assertThat(spec.getCertificateSerialNumber(), is(SERIAL)); @@ -134,7 +134,7 @@ public final class ParcelableKeyGenParameterSpecTest { Parcel parcel = parcelForReading(spec); ParcelableKeyGenParameterSpec fromParcel = ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel); - validateSpecValues(fromParcel.getSpec(), UID, ALIAS); + validateSpecValues(fromParcel.getSpec(), KeyProperties.NAMESPACE_WIFI, ALIAS); assertThat(parcel.dataAvail(), is(0)); } diff --git a/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java b/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java index b2edfd05d13f..ddbb1d8c097c 100644 --- a/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java +++ b/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java @@ -21,8 +21,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import android.security.ParcelableKeyGenParameterSpecTest; -import android.security.keystore.KeyGenParameterSpec; -import android.security.keystore.KeyProperties; import androidx.test.runner.AndroidJUnit4; @@ -41,7 +39,7 @@ public final class KeyGenParameterSpecTest { KeyGenParameterSpec copiedSpec = new KeyGenParameterSpec.Builder(spec).build(); ParcelableKeyGenParameterSpecTest.validateSpecValues( - copiedSpec, spec.getUid(), spec.getKeystoreAlias()); + copiedSpec, spec.getNamespace(), spec.getKeystoreAlias()); } @Test diff --git a/keystore/tests/src/android/security/keystore2/AndroidKeyStoreSpiTest.java b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreSpiTest.java new file mode 100644 index 000000000000..1bd3069f483a --- /dev/null +++ b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreSpiTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore2; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.security.KeyStore2; +import android.security.KeyStoreException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class AndroidKeyStoreSpiTest { + + @Mock + private KeyStore2 mKeystore2; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testEngineAliasesReturnsEmptySetOnKeyStoreError() throws Exception { + when(mKeystore2.list(anyInt(), anyLong())) + .thenThrow(new KeyStoreException(6, "Some Error")); + AndroidKeyStoreSpi spi = new AndroidKeyStoreSpi(); + spi.initForTesting(mKeystore2); + + assertThat("Empty collection expected", !spi.engineAliases().hasMoreElements()); + + verify(mKeystore2).list(anyInt(), anyLong()); + } + +} diff --git a/libs/androidfw/PosixUtils.cpp b/libs/androidfw/PosixUtils.cpp index f1ab1493012a..4ec525a01da5 100644 --- a/libs/androidfw/PosixUtils.cpp +++ b/libs/androidfw/PosixUtils.cpp @@ -72,7 +72,8 @@ std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv) argv0[i] = argv[i].c_str(); } argv0[argv.size()] = nullptr; - switch (fork()) { + int pid = fork(); + switch (pid) { case -1: // error free(argv0); PLOG(ERROR) << "fork"; @@ -104,8 +105,10 @@ std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv) close(stdout[1]); close(stderr[1]); int status; - wait(&status); + waitpid(pid, &status, 0); if (!WIFEXITED(status)) { + close(stdout[0]); + close(stderr[0]); return nullptr; } std::unique_ptr<ProcResult> result(new ProcResult()); diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 6220abed05eb..e74d3966a39b 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -528,6 +528,7 @@ cc_library { "libhwui_defaults", "android_graphics_apex", "android_graphics_jni", + "linker_hugepage_aligned", ], export_header_lib_headers: ["android_graphics_apex_headers"], } diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 139474c1c01d..67a040dba3e7 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -28,6 +28,7 @@ import android.location.LocationManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.telephony.PhoneNumberUtils; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; @@ -160,7 +161,7 @@ public class GpsNetInitiatedHandler { be set to true when the phone is having emergency call, and then will be set to false by mPhoneStateListener when the emergency call ends. */ - mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber(phoneNumber); + mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber); if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency()); } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) { updateLocationMode(); diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index f79fc92477f7..270dffea429e 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -23,6 +23,7 @@ import android.util.SparseIntArray; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; import java.util.Objects; import java.util.TreeSet; @@ -467,9 +468,32 @@ public final class AudioDeviceInfo { * @see AudioFormat * * Note: an empty array indicates that the device supports arbitrary encodings. + * For forward compatibility, applications should ignore entries it does not recognize. */ public @NonNull int[] getEncodings() { - return AudioFormat.filterPublicFormats(mPort.formats()); + final int[] encodings = AudioFormat.filterPublicFormats(mPort.formats()); + boolean hasFloat = false; + boolean hasExtendedIntegerPrecision = false; + + for (int encoding : encodings) { + if (AudioFormat.isEncodingLinearPcm(encoding)) { + if (encoding == AudioFormat.ENCODING_PCM_FLOAT) { + hasFloat = true; + } else if (AudioFormat.getBytesPerSample(encoding) > 2) { + hasExtendedIntegerPrecision = true; + } + } + } + if (hasExtendedIntegerPrecision && !hasFloat) { + // R and earlier compatibility - add ENCODING_PCM_FLOAT to the end + // (replacing the zero pad). This ensures pre-S apps that look + // for ENCODING_PCM_FLOAT continue to see that encoding if the device supports + // extended precision integers. + int[] encodingsPlusFloat = Arrays.copyOf(encodings, encodings.length + 1); + encodingsPlusFloat[encodings.length] = AudioFormat.ENCODING_PCM_FLOAT; + return encodingsPlusFloat; + } + return encodings; } /** diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 090812e39c5f..5885c7dd8b50 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -110,6 +110,24 @@ import java.util.Objects; * <code>AudioTrack</code> as of API {@link android.os.Build.VERSION_CODES#LOLLIPOP} * support <code>ENCODING_PCM_FLOAT</code>. * </li> + * <li> {@link #ENCODING_PCM_24BIT_PACKED}: Introduced in + * API {@link android.os.Build.VERSION_CODES#S}, + * this encoding specifies the audio sample is an + * extended precision 24 bit signed integer + * stored as a 3 Java bytes in a {@code ByteBuffer} or byte array in native endian + * (see {@link java.nio.ByteOrder#nativeOrder()}). + * Each sample has full range from [-8388608, 8388607], + * and can be interpreted as fixed point Q.23 data. + * </li> + * <li> {@link #ENCODING_PCM_32BIT}: Introduced in + * API {@link android.os.Build.VERSION_CODES#S}, + * this encoding specifies the audio sample is an + * extended precision 32 bit signed integer + * stored as a 4 Java bytes in a {@code ByteBuffer} or byte array in native endian + * (see {@link java.nio.ByteOrder#nativeOrder()}). + * Each sample has full range from [-2147483648, 2147483647], + * and can be interpreted as fixed point Q.31 data. + * </li> * </ul> * <p>For compressed audio, the encoding specifies the method of compression, * for example {@link #ENCODING_AC3} and {@link #ENCODING_DTS}. The compressed @@ -285,6 +303,32 @@ public final class AudioFormat implements Parcelable { /** Audio data format: OPUS compressed. */ public static final int ENCODING_OPUS = 20; + /** @hide + * We do not permit legacy short array reads or writes for encodings + * introduced after this threshold. + */ + public static final int ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD = ENCODING_OPUS; + + /** Audio data format: PCM 24 bit per sample packed as 3 bytes. + * Not guaranteed to be supported by devices, may be emulated if not supported. */ + public static final int ENCODING_PCM_24BIT_PACKED = 21; + /** Audio data format: PCM 32 bit per sample. + * Not guaranteed to be supported by devices, may be emulated if not supported. */ + public static final int ENCODING_PCM_32BIT = 22; + + /** Audio data format: MPEG-H baseline profile, level 3 */ + public static final int ENCODING_MPEGH_BL_L3 = 23; + /** Audio data format: MPEG-H baseline profile, level 4 */ + public static final int ENCODING_MPEGH_BL_L4 = 24; + /** Audio data format: MPEG-H low complexity profile, level 3 */ + public static final int ENCODING_MPEGH_LC_L3 = 25; + /** Audio data format: MPEG-H low complexity profile, level 4 */ + public static final int ENCODING_MPEGH_LC_L4 = 26; + /** Audio data format: DTS UHD compressed */ + public static final int ENCODING_DTS_UHD = 27; + /** Audio data format: DRA compressed */ + public static final int ENCODING_DRA = 28; + /** @hide */ public static String toLogFriendlyEncoding(int enc) { switch(enc) { @@ -328,6 +372,22 @@ public final class AudioFormat implements Parcelable { return "ENCODING_DOLBY_MAT"; case ENCODING_OPUS: return "ENCODING_OPUS"; + case ENCODING_PCM_24BIT_PACKED: + return "ENCODING_PCM_24BIT_PACKED"; + case ENCODING_PCM_32BIT: + return "ENCODING_PCM_32BIT"; + case ENCODING_MPEGH_BL_L3: + return "ENCODING_MPEGH_BL_L3"; + case ENCODING_MPEGH_BL_L4: + return "ENCODING_MPEGH_BL_L4"; + case ENCODING_MPEGH_LC_L3: + return "ENCODING_MPEGH_LC_L3"; + case ENCODING_MPEGH_LC_L4: + return "ENCODING_MPEGH_LC_L4"; + case ENCODING_DTS_UHD: + return "ENCODING_DTS_UHD"; + case ENCODING_DRA: + return "ENCODING_DRA"; default : return "invalid encoding " + enc; } @@ -458,13 +518,13 @@ public final class AudioFormat implements Parcelable { * @hide */ // never unhide - public static final int SAMPLE_RATE_HZ_MIN = 4000; + public static final int SAMPLE_RATE_HZ_MIN = AudioSystem.SAMPLE_RATE_HZ_MIN; /** Maximum value for sample rate, * assuming AudioTrack and AudioRecord share the same limitations. * @hide */ // never unhide - public static final int SAMPLE_RATE_HZ_MAX = 192000; + public static final int SAMPLE_RATE_HZ_MAX = AudioSystem.SAMPLE_RATE_HZ_MAX; /** Sample rate will be a route-dependent value. * For AudioTrack, it is usually the sink sample rate, * and for AudioRecord it is usually the source sample rate. @@ -561,17 +621,20 @@ public final class AudioFormat implements Parcelable { public static int getBytesPerSample(int audioFormat) { switch (audioFormat) { - case ENCODING_PCM_8BIT: - return 1; - case ENCODING_PCM_16BIT: - case ENCODING_IEC61937: - case ENCODING_DEFAULT: - return 2; - case ENCODING_PCM_FLOAT: - return 4; - case ENCODING_INVALID: - default: - throw new IllegalArgumentException("Bad audio format " + audioFormat); + case ENCODING_PCM_8BIT: + return 1; + case ENCODING_PCM_16BIT: + case ENCODING_IEC61937: + case ENCODING_DEFAULT: + return 2; + case ENCODING_PCM_24BIT_PACKED: + return 3; + case ENCODING_PCM_FLOAT: + case ENCODING_PCM_32BIT: + return 4; + case ENCODING_INVALID: + default: + throw new IllegalArgumentException("Bad audio format " + audioFormat); } } @@ -598,6 +661,14 @@ public final class AudioFormat implements Parcelable { case ENCODING_E_AC3_JOC: case ENCODING_DOLBY_MAT: case ENCODING_OPUS: + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: + case ENCODING_MPEGH_BL_L3: + case ENCODING_MPEGH_BL_L4: + case ENCODING_MPEGH_LC_L3: + case ENCODING_MPEGH_LC_L4: + case ENCODING_DTS_UHD: + case ENCODING_DRA: return true; default: return false; @@ -627,6 +698,14 @@ public final class AudioFormat implements Parcelable { case ENCODING_E_AC3_JOC: case ENCODING_DOLBY_MAT: case ENCODING_OPUS: + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: + case ENCODING_MPEGH_BL_L3: + case ENCODING_MPEGH_BL_L4: + case ENCODING_MPEGH_LC_L3: + case ENCODING_MPEGH_LC_L4: + case ENCODING_DTS_UHD: + case ENCODING_DRA: return true; default: return false; @@ -641,6 +720,8 @@ public final class AudioFormat implements Parcelable { case ENCODING_PCM_16BIT: case ENCODING_PCM_8BIT: case ENCODING_PCM_FLOAT: + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: case ENCODING_DEFAULT: return true; case ENCODING_AC3: @@ -659,6 +740,12 @@ public final class AudioFormat implements Parcelable { case ENCODING_E_AC3_JOC: case ENCODING_DOLBY_MAT: case ENCODING_OPUS: + case ENCODING_MPEGH_BL_L3: + case ENCODING_MPEGH_BL_L4: + case ENCODING_MPEGH_LC_L3: + case ENCODING_MPEGH_LC_L4: + case ENCODING_DTS_UHD: + case ENCODING_DRA: return false; case ENCODING_INVALID: default: @@ -674,6 +761,8 @@ public final class AudioFormat implements Parcelable { case ENCODING_PCM_8BIT: case ENCODING_PCM_FLOAT: case ENCODING_IEC61937: // same size as stereo PCM + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: case ENCODING_DEFAULT: return true; case ENCODING_AC3: @@ -691,6 +780,12 @@ public final class AudioFormat implements Parcelable { case ENCODING_E_AC3_JOC: case ENCODING_DOLBY_MAT: case ENCODING_OPUS: + case ENCODING_MPEGH_BL_L3: + case ENCODING_MPEGH_BL_L4: + case ENCODING_MPEGH_LC_L3: + case ENCODING_MPEGH_LC_L4: + case ENCODING_DTS_UHD: + case ENCODING_DRA: return false; case ENCODING_INVALID: default: @@ -971,6 +1066,14 @@ public final class AudioFormat implements Parcelable { case ENCODING_E_AC3_JOC: case ENCODING_DOLBY_MAT: case ENCODING_OPUS: + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: + case ENCODING_MPEGH_BL_L3: + case ENCODING_MPEGH_BL_L4: + case ENCODING_MPEGH_LC_L3: + case ENCODING_MPEGH_LC_L4: + case ENCODING_DTS_UHD: + case ENCODING_DRA: mEncoding = encoding; break; case ENCODING_INVALID: @@ -1191,7 +1294,15 @@ public final class AudioFormat implements Parcelable { ENCODING_AC4, ENCODING_E_AC3_JOC, ENCODING_DOLBY_MAT, - ENCODING_OPUS } + ENCODING_OPUS, + ENCODING_PCM_24BIT_PACKED, + ENCODING_PCM_32BIT, + ENCODING_MPEGH_BL_L3, + ENCODING_MPEGH_BL_L4, + ENCODING_MPEGH_LC_L3, + ENCODING_MPEGH_LC_L4, + ENCODING_DTS_UHD, + ENCODING_DRA } ) @Retention(RetentionPolicy.SOURCE) public @interface Encoding {} @@ -1207,6 +1318,12 @@ public final class AudioFormat implements Parcelable { ENCODING_AC4, ENCODING_E_AC3_JOC, ENCODING_DOLBY_MAT, + ENCODING_MPEGH_BL_L3, + ENCODING_MPEGH_BL_L4, + ENCODING_MPEGH_LC_L3, + ENCODING_MPEGH_LC_L4, + ENCODING_DTS_UHD, + ENCODING_DRA }; /** @hide */ @@ -1219,7 +1336,13 @@ public final class AudioFormat implements Parcelable { ENCODING_DOLBY_TRUEHD, ENCODING_AC4, ENCODING_E_AC3_JOC, - ENCODING_DOLBY_MAT } + ENCODING_DOLBY_MAT, + ENCODING_MPEGH_BL_L3, + ENCODING_MPEGH_BL_L4, + ENCODING_MPEGH_LC_L3, + ENCODING_MPEGH_LC_L4, + ENCODING_DTS_UHD, + ENCODING_DRA } ) @Retention(RetentionPolicy.SOURCE) public @interface SurroundSoundEncoding {} @@ -1253,6 +1376,18 @@ public final class AudioFormat implements Parcelable { return "Dolby Atmos in Dolby Digital Plus"; case ENCODING_DOLBY_MAT: return "Dolby MAT"; + case ENCODING_MPEGH_BL_L3: + return "MPEG-H 3D Audio baseline profile level 3"; + case ENCODING_MPEGH_BL_L4: + return "MPEG-H 3D Audio baseline profile level 4"; + case ENCODING_MPEGH_LC_L3: + return "MPEG-H 3D Audio low complexity profile level 3"; + case ENCODING_MPEGH_LC_L4: + return "MPEG-H 3D Audio low complexity profile level 4"; + case ENCODING_DTS_UHD: + return "DTS UHD"; + case ENCODING_DRA: + return "DRA"; default: return "Unknown surround sound format"; } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index d670f073fe8b..52233b65ce6d 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -845,17 +845,21 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, //-------------- // audio format switch (audioFormat) { - case AudioFormat.ENCODING_DEFAULT: - mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; - break; - case AudioFormat.ENCODING_PCM_FLOAT: - case AudioFormat.ENCODING_PCM_16BIT: - case AudioFormat.ENCODING_PCM_8BIT: - mAudioFormat = audioFormat; - break; - default: - throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat - + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT."); + case AudioFormat.ENCODING_DEFAULT: + mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; + break; + case AudioFormat.ENCODING_PCM_24BIT_PACKED: + case AudioFormat.ENCODING_PCM_32BIT: + case AudioFormat.ENCODING_PCM_FLOAT: + case AudioFormat.ENCODING_PCM_16BIT: + case AudioFormat.ENCODING_PCM_8BIT: + mAudioFormat = audioFormat; + break; + default: + throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat + + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT," + + " ENCODING_PCM_24BIT_PACKED, ENCODING_PCM_32BIT," + + " or ENCODING_PCM_FLOAT."); } } @@ -1262,6 +1266,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, */ public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode) { + // Note: we allow reads of extended integers into a byte array. if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { return ERROR_INVALID_OPERATION; } @@ -1334,7 +1339,10 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, */ public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, @ReadMode int readMode) { - if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { + if (mState != STATE_INITIALIZED + || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT + // use ByteBuffer instead for later encodings + || mAudioFormat > AudioFormat.ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD) { return ERROR_INVALID_OPERATION; } diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 18c8a72b165b..313196597619 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -101,11 +101,34 @@ public class AudioSystem */ public static final int NUM_STREAMS = 5; + /* + * Framework static final constants that are primitives or Strings + * accessed by CTS tests or internal applications must be set from methods + * (or in a static block) to prevent Java compile-time replacement. + * We set them from methods so they are read from the device framework. + * Do not un-hide or change to a numeric literal. + */ + /** Maximum value for AudioTrack channel count - * @hide public for MediaCode only, do not un-hide or change to a numeric literal + * @hide + */ + public static final int OUT_CHANNEL_COUNT_MAX = native_getMaxChannelCount(); + private static native int native_getMaxChannelCount(); + + /** Maximum value for sample rate, used by AudioFormat. + * @hide + */ + public static final int SAMPLE_RATE_HZ_MAX = native_getMaxSampleRate(); + private static native int native_getMaxSampleRate(); + + /** Minimum value for sample rate, used by AudioFormat. + * @hide */ - public static final int OUT_CHANNEL_COUNT_MAX = native_get_FCC_8(); - private static native int native_get_FCC_8(); + public static final int SAMPLE_RATE_HZ_MIN = native_getMinSampleRate(); + private static native int native_getMinSampleRate(); + + /** @hide */ + public static final int FCC_24 = 24; // fixed channel count 24; do not change. // Expose only the getter method publicly so we can change it in the future private static final int NUM_STREAM_TYPES = 12; @@ -424,6 +447,10 @@ public class AudioSystem return "AUDIO_FORMAT_MAT_2_0"; // (MAT | MAT_SUB_2_0) case /* AUDIO_FORMAT_MAT_2_1 */ 0x24000003: return "AUDIO_FORMAT_MAT_2_1"; // (MAT | MAT_SUB_2_1) + case /* AUDIO_FORMAT_DTS_UHD */ 0x2E000000: + return "AUDIO_FORMAT_DTS_UHD"; + case /* AUDIO_FORMAT_DRA */ 0x2F000000: + return "AUDIO_FORMAT_DRA"; default: return "AUDIO_FORMAT_(" + audioFormat + ")"; } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 67880a589b43..68ce5e7b80ee 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -1712,9 +1712,10 @@ public class AudioTrack extends PlayerBase mChannelCount = 0; break; // channel index configuration only } - if (!isMultichannelConfigSupported(channelConfig)) { - // input channel configuration features unsupported channels - throw new IllegalArgumentException("Unsupported channel configuration."); + if (!isMultichannelConfigSupported(channelConfig, audioFormat)) { + throw new IllegalArgumentException( + "Unsupported channel mask configuration " + channelConfig + + " for encoding " + audioFormat); } mChannelMask = channelConfig; mChannelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig); @@ -1722,13 +1723,17 @@ public class AudioTrack extends PlayerBase // check the channel index configuration (if present) mChannelIndexMask = channelIndexMask; if (mChannelIndexMask != 0) { - // restrictive: indexMask could allow up to AUDIO_CHANNEL_BITS_LOG2 - final int indexMask = (1 << AudioSystem.OUT_CHANNEL_COUNT_MAX) - 1; - if ((channelIndexMask & ~indexMask) != 0) { - throw new IllegalArgumentException("Unsupported channel index configuration " - + channelIndexMask); + // As of S, we accept up to 24 channel index mask. + final int fullIndexMask = (1 << AudioSystem.FCC_24) - 1; + final int channelIndexCount = Integer.bitCount(channelIndexMask); + final boolean accepted = (channelIndexMask & ~fullIndexMask) == 0 + && (!AudioFormat.isEncodingLinearFrames(audioFormat) // compressed OK + || channelIndexCount <= AudioSystem.OUT_CHANNEL_COUNT_MAX); // PCM + if (!accepted) { + throw new IllegalArgumentException( + "Unsupported channel index mask configuration " + channelIndexMask + + " for encoding " + audioFormat); } - int channelIndexCount = Integer.bitCount(channelIndexMask); if (mChannelCount == 0) { mChannelCount = channelIndexCount; } else if (mChannelCount != channelIndexCount) { @@ -1781,16 +1786,19 @@ public class AudioTrack extends PlayerBase * @param channelConfig the mask to validate * @return false if the AudioTrack can't be used with such a mask */ - private static boolean isMultichannelConfigSupported(int channelConfig) { + private static boolean isMultichannelConfigSupported(int channelConfig, int encoding) { // check for unsupported channels if ((channelConfig & SUPPORTED_OUT_CHANNELS) != channelConfig) { loge("Channel configuration features unsupported channels"); return false; } final int channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig); - if (channelCount > AudioSystem.OUT_CHANNEL_COUNT_MAX) { - loge("Channel configuration contains too many channels " + - channelCount + ">" + AudioSystem.OUT_CHANNEL_COUNT_MAX); + final int channelCountLimit = AudioFormat.isEncodingLinearFrames(encoding) + ? AudioSystem.OUT_CHANNEL_COUNT_MAX // PCM limited to OUT_CHANNEL_COUNT_MAX + : AudioSystem.FCC_24; // Compressed limited to 24 channels + if (channelCount > channelCountLimit) { + loge("Channel configuration contains too many channels for encoding " + + encoding + "(" + channelCount + " > " + channelCountLimit + ")"); return false; } // check for unsupported multichannel combinations: @@ -2301,7 +2309,7 @@ public class AudioTrack extends PlayerBase channelCount = 2; break; default: - if (!isMultichannelConfigSupported(channelConfig)) { + if (!isMultichannelConfigSupported(channelConfig, audioFormat)) { loge("getMinBufferSize(): Invalid channel configuration."); return ERROR_BAD_VALUE; } else { @@ -2992,7 +3000,7 @@ public class AudioTrack extends PlayerBase */ public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, @WriteMode int writeMode) { - + // Note: we allow writes of extended integers and compressed formats from a byte array. if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { return ERROR_INVALID_OPERATION; } @@ -3106,7 +3114,10 @@ public class AudioTrack extends PlayerBase public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, @WriteMode int writeMode) { - if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { + if (mState == STATE_UNINITIALIZED + || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT + // use ByteBuffer or byte[] instead for later encodings + || mAudioFormat > AudioFormat.ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD) { return ERROR_INVALID_OPERATION; } diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 13c690770f49..17f3e96250da 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -169,6 +169,10 @@ public final class MediaFormat { public static final String MIMETYPE_AUDIO_EAC3_JOC = "audio/eac3-joc"; public static final String MIMETYPE_AUDIO_AC4 = "audio/ac4"; public static final String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled"; + /** MIME type for MPEG-H Audio single stream */ + public static final String MIMETYPE_AUDIO_MPEGH_MHA1 = "audio/mha1"; + /** MIME type for MPEG-H Audio single stream, encapsulated in MHAS */ + public static final String MIMETYPE_AUDIO_MPEGH_MHM1 = "audio/mhm1"; /** * MIME type for HEIF still image data encoded in HEVC. diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java index 11d20d4d6c80..bcd0eb0a9e39 100644 --- a/mime/java/android/content/type/DefaultMimeMapFactory.java +++ b/mime/java/android/content/type/DefaultMimeMapFactory.java @@ -96,7 +96,7 @@ public class DefaultMimeMapFactory { specs.add(spec); startIdx = endIdx + 1; // skip over the space } while (startIdx < line.length()); - builder.put(specs.get(0), specs.subList(1, specs.size())); + builder.addMimeMapping(specs.get(0), specs.subList(1, specs.size())); } } catch (IOException | RuntimeException e) { throw new RuntimeException("Failed to parse " + resourceName, e); diff --git a/native/android/Android.bp b/native/android/Android.bp index 2a2b08d77e21..dda230d10137 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -115,7 +115,11 @@ cc_library_shared { cc_library_shared { name: "libandroid_net", defaults: ["libandroid_defaults"], - llndk_stubs: "libandroid_net.llndk", + llndk: { + symbol_file: "libandroid_net.map.txt", + unversioned: true, + override_export_include_dirs: ["include"], + }, srcs: ["net.c"], shared_libs: ["libnetd_client"], @@ -123,13 +127,6 @@ cc_library_shared { include_dirs: ["bionic/libc/dns/include"], } -llndk_library { - name: "libandroid_net.llndk", - export_include_dirs: ["include"], - symbol_file: "libandroid_net.map.txt", - unversioned: true, -} - // Aidl library for platform compat. cc_library_shared { name: "lib-platform-compat-native-api", diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp index 017ff51f366d..657d5a3d2eae 100644 --- a/packages/Connectivity/framework/Android.bp +++ b/packages/Connectivity/framework/Android.bp @@ -25,6 +25,7 @@ package { java_library { name: "framework-connectivity-protos", + sdk_version: "module_current", proto: { type: "nano", }, @@ -82,8 +83,7 @@ java_sdk_library { name: "framework-connectivity", api_only: true, defaults: ["framework-module-defaults"], - // TODO: build against module API - platform_apis: true, + installable: true, srcs: [ ":framework-connectivity-sources", ], @@ -100,18 +100,56 @@ java_sdk_library { libs: [ "unsupportedappusage", ], - permitted_packages: ["android.net", "com.android.connectivity.aidl"], + permitted_packages: ["android.net"], +} + +cc_defaults { + name: "libframework-connectivity-defaults", + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + "-Wthread-safety", + ], + shared_libs: [ + "libbase", + "liblog", + "libnativehelper", + "libnetd_client", + ], + header_libs: [ + "dnsproxyd_protocol_headers", + ], +} + +cc_library_static { + name: "libconnectivityframeworkutils", + defaults: ["libframework-connectivity-defaults"], + srcs: [ + "jni/android_net_NetworkUtils.cpp", + ], + apex_available: [ + "//apex_available:platform", + "com.android.tethering", + ], +} + +cc_library_shared { + name: "libframework-connectivity-jni", + defaults: ["libframework-connectivity-defaults"], + srcs: [ + "jni/onload.cpp", + ], + static_libs: ["libconnectivityframeworkutils"], + apex_available: [ + "//apex_available:platform", + "com.android.tethering", + ], } java_library { name: "framework-connectivity.impl", - // Instead of building against private API (framework.jar), - // build against core_platform + framework-minus-apex + module - // stub libs. This allows framework.jar to depend on this library, - // so it can be part of the private API until all clients have been migrated. - // TODO: just build against module_api, and remove this jar from - // the private API. - sdk_version: "core_platform", + sdk_version: "module_current", srcs: [ ":framework-connectivity-sources", ], @@ -122,12 +160,11 @@ java_library { ], }, libs: [ - "framework-minus-apex", - // TODO: just framework-tethering, framework-wifi when building against module_api - "framework-tethering.stubs.module_lib", - "framework-wifi.stubs.module_lib", + // TODO (b/183097033) remove once module_current includes core_current + "stable.core.platform.api.stubs", + "framework-tethering", + "framework-wifi", "unsupportedappusage", - "ServiceConnectivityResources", ], static_libs: [ "framework-connectivity-protos", @@ -136,5 +173,5 @@ java_library { jarjar_rules: "jarjar-rules.txt", apex_available: ["com.android.tethering"], installable: true, - permitted_packages: ["android.net", "com.android.connectivity.aidl"], + permitted_packages: ["android.net"], } diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index 9e2cd3e8a7fd..6c454bcd4cd7 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -7,11 +7,10 @@ package android.net { public class ConnectivityManager { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void factoryReset(); - method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot(); + method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots(); method @Nullable public android.net.ProxyInfo getGlobalProxy(); method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange(); - method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackAsUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress); @@ -20,7 +19,6 @@ package android.net { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network); method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean); - method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String); method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); @@ -40,9 +38,6 @@ package android.net { field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10 field public static final int BLOCKED_REASON_NONE = 0; // 0x0 field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8 - field public static final String PRIVATE_DNS_MODE_OFF = "off"; - field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; - field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname"; field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0 field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1 } @@ -53,6 +48,7 @@ package android.net { public class ConnectivitySettingsManager { method public static void clearGlobalProxy(@NonNull android.content.Context); + method @NonNull public static java.util.Set<java.lang.String> getAppsAllowedOnRestrictedNetworks(@NonNull android.content.Context); method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context); method public static int getCaptivePortalMode(@NonNull android.content.Context, int); method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration); @@ -62,15 +58,17 @@ package android.net { method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context); method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean); - method @Nullable public static String getMobileDataPreferredApps(@NonNull android.content.Context); + method @NonNull public static java.util.Set<java.lang.Integer> getMobileDataPreferredUids(@NonNull android.content.Context); method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context); method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context); method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int); method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration); method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context); method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context); + method public static int getPrivateDnsMode(@NonNull android.content.Context); method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean); method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setAppsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.String>); method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String); method public static void setCaptivePortalMode(@NonNull android.content.Context, int); method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration); @@ -80,13 +78,14 @@ package android.net { method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo); method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean); - method public static void setMobileDataPreferredApps(@NonNull android.content.Context, @Nullable String); + method public static void setMobileDataPreferredUids(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>); method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int); method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String); method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int); method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration); - method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String); + method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int); method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String); + method public static void setPrivateDnsMode(@NonNull android.content.Context, int); method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean); method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2 @@ -95,6 +94,9 @@ package android.net { field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2 field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0 field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1 + field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1 + field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2 + field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3 } public final class NetworkAgentConfig implements android.os.Parcelable { @@ -109,7 +111,7 @@ package android.net { public final class NetworkCapabilities implements android.os.Parcelable { method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids(); - method public boolean hasUnwantedCapability(int); + method public boolean hasForbiddenCapability(int); field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L @@ -123,13 +125,13 @@ package android.net { } public class NetworkRequest implements android.os.Parcelable { - method @NonNull public int[] getUnwantedCapabilities(); - method public boolean hasUnwantedCapability(int); + method @NonNull public int[] getForbiddenCapabilities(); + method public boolean hasForbiddenCapability(int); } public static class NetworkRequest.Builder { - method @NonNull public android.net.NetworkRequest.Builder addUnwantedCapability(int); - method @NonNull public android.net.NetworkRequest.Builder removeUnwantedCapability(int); + method @NonNull public android.net.NetworkRequest.Builder addForbiddenCapability(int); + method @NonNull public android.net.NetworkRequest.Builder removeForbiddenCapability(int); method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>); } @@ -166,11 +168,11 @@ package android.net { public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo { ctor public VpnTransportInfo(int, @Nullable String); method public int describeContents(); + method @Nullable public String getSessionId(); + method public int getType(); method @NonNull public android.net.VpnTransportInfo makeCopy(long); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR; - field @Nullable public final String sessionId; - field public final int type; } } diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt index 935b09330c6c..27bf114b5229 100644 --- a/packages/Connectivity/framework/api/system-current.txt +++ b/packages/Connectivity/framework/api/system-current.txt @@ -238,7 +238,7 @@ package android.net { method public final void sendQosSessionLost(int, int, int); method public final void sendSocketKeepaliveEvent(int, int); method @Deprecated public void setLegacySubtype(int, @NonNull String); - method public void setTeardownDelayMs(@IntRange(from=0, to=0x1388) int); + method public void setTeardownDelayMillis(@IntRange(from=0, to=0x1388) int); method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>); method public void unregister(); field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2 @@ -294,7 +294,6 @@ package android.net { method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int); method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int); method @NonNull public android.net.NetworkCapabilities build(); - method @NonNull public android.net.NetworkCapabilities.Builder clearAll(); method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int); method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int); method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]); @@ -308,6 +307,7 @@ package android.net { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String); method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>); method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo); + method @NonNull public static android.net.NetworkCapabilities.Builder withoutDefaultCapabilities(); } public class NetworkProvider { @@ -381,6 +381,7 @@ package android.net { public abstract class QosFilter { method @NonNull public abstract android.net.Network getNetwork(); method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int); + method public abstract boolean matchesRemoteAddress(@NonNull java.net.InetAddress, int, int); } public final class QosSession implements android.os.Parcelable { @@ -403,6 +404,7 @@ package android.net { method public int describeContents(); method @NonNull public java.net.InetSocketAddress getLocalSocketAddress(); method @NonNull public android.net.Network getNetwork(); + method @Nullable public java.net.InetSocketAddress getRemoteSocketAddress(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR; } diff --git a/core/jni/android_net_NetworkUtils.cpp b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp index 1cee8955a7a2..48e262a6b19b 100644 --- a/core/jni/android_net_NetworkUtils.cpp +++ b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp @@ -30,13 +30,13 @@ #include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS #include <cutils/properties.h> +#include <nativehelper/JNIHelp.h> #include <nativehelper/JNIPlatformHelp.h> #include <nativehelper/ScopedLocalRef.h> #include <utils/Log.h> #include <utils/misc.h> #include "NetdClient.h" -#include "core_jni_helpers.h" #include "jni.h" extern "C" { @@ -52,6 +52,19 @@ constexpr int MAXPACKETSIZE = 8 * 1024; // FrameworkListener limits the size of commands to 4096 bytes. constexpr int MAXCMDSIZE = 4096; +static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) { + jclass clazz = env->FindClass(class_name); + LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name); + return clazz; +} + +template <typename T> +static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) { + jobject res = env->NewGlobalRef(in); + LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to create global reference."); + return static_cast<T>(res); +} + static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd) { struct sock_filter filter_code[] = { @@ -254,8 +267,8 @@ static const JNINativeMethod gNetworkUtilMethods[] = { int register_android_net_NetworkUtils(JNIEnv* env) { - return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods, - NELEM(gNetworkUtilMethods)); + return jniRegisterNativeMethods(env, NETUTILS_PKG_NAME, gNetworkUtilMethods, + NELEM(gNetworkUtilMethods)); } }; // namespace android diff --git a/core/java/com/android/internal/annotations/Immutable.java b/packages/Connectivity/framework/jni/onload.cpp index b424275f7a86..435f4343ed14 100644 --- a/core/java/com/android/internal/annotations/Immutable.java +++ b/packages/Connectivity/framework/jni/onload.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,25 @@ * limitations under the License. */ -package com.android.internal.annotations; +#include <nativehelper/JNIHelp.h> +#include <log/log.h> -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +namespace android { -/** - * Annotation type used to mark a class which is immutable. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.CLASS) -public @interface Immutable { +int register_android_net_NetworkUtils(JNIEnv* env); + +extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + ALOGE("GetEnv failed"); + return JNI_ERR; + } + + if (register_android_net_NetworkUtils(env) < 0) { + return JNI_ERR; + } + + return JNI_VERSION_1_6; } + +};
\ No newline at end of file diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index 4dd0984c79fd..1a6b37bfdb42 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -16,8 +16,6 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE; -import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE; import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST; import static android.net.NetworkRequest.Type.LISTEN; import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST; @@ -33,7 +31,6 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.StringDef; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -41,7 +38,6 @@ import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod; @@ -70,7 +66,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Range; @@ -821,38 +816,6 @@ public class ConnectivityManager { public static final int NETID_UNSET = 0; /** - * Private DNS Mode values. - * - * The "private_dns_mode" global setting stores a String value which is - * expected to be one of the following. - */ - - /** - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final String PRIVATE_DNS_MODE_OFF = "off"; - /** - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; - /** - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname"; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @StringDef(value = { - PRIVATE_DNS_MODE_OFF, - PRIVATE_DNS_MODE_OPPORTUNISTIC, - PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, - }) - public @interface PrivateDnsMode {} - - /** * Flag to indicate that an app is not subject to any restrictions that could result in its * network access blocked. * @@ -1435,9 +1398,9 @@ public class ConnectivityManager { android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) @NonNull - public List<NetworkStateSnapshot> getAllNetworkStateSnapshot() { + public List<NetworkStateSnapshot> getAllNetworkStateSnapshots() { try { - return mService.getAllNetworkStateSnapshot(); + return mService.getAllNetworkStateSnapshots(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1561,7 +1524,7 @@ public class ConnectivityManager { /** * Get the {@link NetworkCapabilities} for the given {@link Network}. This - * will return {@code null} if the network is unknown. + * will return {@code null} if the network is unknown or if the |network| argument is null. * * This will remove any location sensitive data in {@link TransportInfo} embedded in * {@link NetworkCapabilities#getTransportInfo()}. Some transport info instances like @@ -3374,7 +3337,60 @@ public class ConnectivityManager { provider.setProviderId(NetworkProvider.ID_NONE); } + /** + * Register or update a network offer with ConnectivityService. + * + * ConnectivityService keeps track of offers made by the various providers and matches + * them to networking requests made by apps or the system. The provider supplies a score + * and the capabilities of the network it might be able to bring up ; these act as filters + * used by ConnectivityService to only send those requests that can be fulfilled by the + * provider. + * + * The provider is under no obligation to be able to bring up the network it offers at any + * given time. Instead, this mechanism is meant to limit requests received by providers + * to those they actually have a chance to fulfill, as providers don't have a way to compare + * the quality of the network satisfying a given request to their own offer. + * + * An offer can be updated by calling this again with the same callback object. This is + * similar to calling unofferNetwork and offerNetwork again, but will only update the + * provider with the changes caused by the changes in the offer. + * + * @param provider The provider making this offer. + * @param score The prospective score of the network. + * @param caps The prospective capabilities of the network. + * @param callback The callback to call when this offer is needed or unneeded. + * @hide + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_FACTORY}) + public void offerNetwork(@NonNull final NetworkProvider provider, + @NonNull final NetworkScore score, @NonNull final NetworkCapabilities caps, + @NonNull final INetworkOfferCallback callback) { + try { + mService.offerNetwork(Objects.requireNonNull(provider.getMessenger(), "null messenger"), + Objects.requireNonNull(score, "null score"), + Objects.requireNonNull(caps, "null caps"), + Objects.requireNonNull(callback, "null callback")); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** + * Withdraw a network offer made with {@link #offerNetwork}. + * + * @param callback The callback passed at registration time. This must be the same object + * that was passed to {@link #offerNetwork} + * @hide + */ + public void unofferNetwork(@NonNull final INetworkOfferCallback callback) { + try { + mService.unofferNetwork(Objects.requireNonNull(callback)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } /** @hide exposed via the NetworkProvider class. */ @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, @@ -4418,7 +4434,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback, @NonNull Handler handler) { - registerDefaultNetworkCallbackAsUid(Process.INVALID_UID, networkCallback, handler); + registerDefaultNetworkCallbackForUid(Process.INVALID_UID, networkCallback, handler); } /** @@ -4448,7 +4464,7 @@ public class ConnectivityManager { @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) - public void registerDefaultNetworkCallbackAsUid(int uid, + public void registerDefaultNetworkCallbackForUid(int uid, @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { CallbackHandler cbHandler = new CallbackHandler(handler); sendRequestForNetwork(uid, null /* need */, networkCallback, 0 /* timeoutMs */, @@ -5448,44 +5464,4 @@ public class ConnectivityManager { public static Range<Integer> getIpSecNetIdRange() { return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1); } - - /** - * Get private DNS mode from settings. - * - * @param context The Context to query the private DNS mode from settings. - * @return A string of private DNS mode as one of the PRIVATE_DNS_MODE_* constants. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @NonNull - @PrivateDnsMode - public static String getPrivateDnsMode(@NonNull Context context) { - final ContentResolver cr = context.getContentResolver(); - String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); - if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); - // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose - // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. - if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC; - return mode; - } - - /** - * Set private DNS mode to settings. - * - * @param context The {@link Context} to set the private DNS mode. - * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static void setPrivateDnsMode(@NonNull Context context, - @NonNull @PrivateDnsMode String mode) { - if (!(mode == PRIVATE_DNS_MODE_OFF - || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC - || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { - throw new IllegalArgumentException("Invalid private dns mode"); - } - Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode); - } } diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java index 9a00055e0079..762f24f7e79a 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java @@ -19,20 +19,20 @@ package android.net; import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER; import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE; import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.content.ContentResolver; import android.content.Context; import android.net.ConnectivityManager.MultipathPreference; -import android.net.ConnectivityManager.PrivateDnsMode; +import android.os.Process; +import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Range; import com.android.net.module.util.ProxyUtils; @@ -41,6 +41,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Duration; import java.util.List; +import java.util.Set; +import java.util.StringJoiner; /** * A manager class for connectivity module settings. @@ -333,12 +335,51 @@ public class ConnectivitySettingsManager { "network_metered_multipath_preference"; /** - * A list of apps that should go on cellular networks in preference even when higher-priority + * A list of uids that should go on cellular networks in preference even when higher-priority * networks are connected. * * @hide */ - public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps"; + public static final String MOBILE_DATA_PREFERRED_UIDS = "mobile_data_preferred_uids"; + + /** + * One of the private DNS modes that indicates the private DNS mode is off. + */ + public static final int PRIVATE_DNS_MODE_OFF = 1; + + /** + * One of the private DNS modes that indicates the private DNS mode is automatic, which + * will try to use the current DNS as private DNS. + */ + public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; + + /** + * One of the private DNS modes that indicates the private DNS mode is strict and the + * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of + * {@link #PRIVATE_DNS_SPECIFIER} as private DNS. + */ + public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + PRIVATE_DNS_MODE_OFF, + PRIVATE_DNS_MODE_OPPORTUNISTIC, + PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, + }) + public @interface PrivateDnsMode {} + + private static final String PRIVATE_DNS_MODE_OFF_STRING = "off"; + private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic"; + private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname"; + + /** + * A list of apps that is allowed on restricted networks. + * + * @hide + */ + public static final String APPS_ALLOWED_ON_RESTRICTED_NETWORKS = + "apps_allowed_on_restricted_networks"; /** * Get mobile data activity timeout from {@link Settings}. @@ -689,6 +730,65 @@ public class ConnectivitySettingsManager { context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */); } + private static String getPrivateDnsModeAsString(@PrivateDnsMode int mode) { + switch (mode) { + case PRIVATE_DNS_MODE_OFF: + return PRIVATE_DNS_MODE_OFF_STRING; + case PRIVATE_DNS_MODE_OPPORTUNISTIC: + return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING; + case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + private static int getPrivateDnsModeAsInt(String mode) { + switch (mode) { + case "off": + return PRIVATE_DNS_MODE_OFF; + case "hostname": + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; + case "opportunistic": + return PRIVATE_DNS_MODE_OPPORTUNISTIC; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + /** + * Get private DNS mode from settings. + * + * @param context The Context to query the private DNS mode from settings. + * @return A string of private DNS mode. + */ + @PrivateDnsMode + public static int getPrivateDnsMode(@NonNull Context context) { + final ContentResolver cr = context.getContentResolver(); + String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); + if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); + // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose + // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. + if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC; + return getPrivateDnsModeAsInt(mode); + } + + /** + * Set private DNS mode to settings. + * + * @param context The {@link Context} to set the private DNS mode. + * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. + */ + public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) { + if (!(mode == PRIVATE_DNS_MODE_OFF + || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC + || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, + getPrivateDnsModeAsString(mode)); + } + /** * Get specific private dns provider name from {@link Settings}. * @@ -731,13 +831,14 @@ public class ConnectivitySettingsManager { * constants. */ public static void setPrivateDnsDefaultMode(@NonNull Context context, - @NonNull @PrivateDnsMode String mode) { + @NonNull @PrivateDnsMode int mode) { if (!(mode == PRIVATE_DNS_MODE_OFF || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { throw new IllegalArgumentException("Invalid private dns mode"); } - Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode); + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, + getPrivateDnsModeAsString(mode)); } /** @@ -903,27 +1004,84 @@ public class ConnectivitySettingsManager { } /** - * Get the list of apps(from {@link Settings}) that should go on cellular networks in preference + * Get the list of uids(from {@link Settings}) that should go on cellular networks in preference * even when higher-priority networks are connected. * * @param context The {@link Context} to query the setting. - * @return A list of apps that should go on cellular networks in preference even when + * @return A list of uids that should go on cellular networks in preference even when * higher-priority networks are connected or null if no setting value. */ - @Nullable - public static String getMobileDataPreferredApps(@NonNull Context context) { - return Settings.Secure.getString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS); + @NonNull + public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) { + final String uidList = Settings.Secure.getString( + context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS); + final Set<Integer> uids = new ArraySet<>(); + if (TextUtils.isEmpty(uidList)) { + return uids; + } + for (String uid : uidList.split(";")) { + uids.add(Integer.valueOf(uid)); + } + return uids; } /** - * Set the list of apps(to {@link Settings}) that should go on cellular networks in preference + * Set the list of uids(to {@link Settings}) that should go on cellular networks in preference * even when higher-priority networks are connected. * * @param context The {@link Context} to set the setting. - * @param list A list of apps that should go on cellular networks in preference even when + * @param uidList A list of uids that should go on cellular networks in preference even when * higher-priority networks are connected. */ - public static void setMobileDataPreferredApps(@NonNull Context context, @Nullable String list) { - Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS, list); + public static void setMobileDataPreferredUids(@NonNull Context context, + @NonNull Set<Integer> uidList) { + final StringJoiner joiner = new StringJoiner(";"); + for (Integer uid : uidList) { + if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) { + throw new IllegalArgumentException("Invalid uid"); + } + joiner.add(uid.toString()); + } + Settings.Secure.putString( + context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, joiner.toString()); + } + + /** + * Get the list of apps(from {@link Settings}) that is allowed on restricted networks. + * + * @param context The {@link Context} to query the setting. + * @return A list of apps that is allowed on restricted networks or null if no setting + * value. + */ + @NonNull + public static Set<String> getAppsAllowedOnRestrictedNetworks(@NonNull Context context) { + final String appList = Settings.Secure.getString( + context.getContentResolver(), APPS_ALLOWED_ON_RESTRICTED_NETWORKS); + if (TextUtils.isEmpty(appList)) { + return new ArraySet<>(); + } + return new ArraySet<>(appList.split(";")); + } + + /** + * Set the list of apps(from {@link Settings}) that is allowed on restricted networks. + * + * Note: Please refer to android developer guidelines for valid app(package name). + * https://developer.android.com/guide/topics/manifest/manifest-element.html#package + * + * @param context The {@link Context} to set the setting. + * @param list A list of apps that is allowed on restricted networks. + */ + public static void setAppsAllowedOnRestrictedNetworks(@NonNull Context context, + @NonNull Set<String> list) { + final StringJoiner joiner = new StringJoiner(";"); + for (String app : list) { + if (app == null || app.contains(";")) { + throw new IllegalArgumentException("Invalid app(package name)"); + } + joiner.add(app); + } + Settings.Secure.putString(context.getContentResolver(), APPS_ALLOWED_ON_RESTRICTED_NETWORKS, + joiner.toString()); } } diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl index 0826922e2165..d937c9cd78c0 100644 --- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl +++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl @@ -23,6 +23,7 @@ import android.net.IConnectivityDiagnosticsCallback; import android.net.INetworkAgent; import android.net.IOnCompleteListener; import android.net.INetworkActivityListener; +import android.net.INetworkOfferCallback; import android.net.IQosCallback; import android.net.ISocketKeepaliveCallback; import android.net.LinkProperties; @@ -81,7 +82,7 @@ interface IConnectivityManager @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) NetworkState[] getAllNetworkState(); - List<NetworkStateSnapshot> getAllNetworkStateSnapshot(); + List<NetworkStateSnapshot> getAllNetworkStateSnapshots(); boolean isActiveNetworkMetered(); @@ -221,4 +222,8 @@ interface IConnectivityManager in IOnCompleteListener listener); int getRestrictBackgroundStatusByCaller(); + + void offerNetwork(in Messenger messenger, in NetworkScore score, + in NetworkCapabilities caps, in INetworkOfferCallback callback); + void unofferNetwork(in INetworkOfferCallback callback); } diff --git a/packages/Connectivity/framework/src/android/net/INetworkOfferCallback.aidl b/packages/Connectivity/framework/src/android/net/INetworkOfferCallback.aidl new file mode 100644 index 000000000000..67d2d405dbed --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/INetworkOfferCallback.aidl @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.NetworkRequest; + +/** + * A callback registered with connectivity by network providers together with + * a NetworkOffer. + * + * When the offer is needed to satisfy some application or system component, + * connectivity will call onOfferNeeded on this callback. When this happens, + * the provider should try and bring up the network. + * + * When the offer is no longer needed, for example because the application has + * withdrawn the request or if the request is being satisfied by a network + * that this offer will never be able to beat, connectivity calls + * onOfferUnneeded. When this happens, the provider should stop trying to + * bring up the network, or tear it down if it has already been brought up. + * + * When NetworkProvider#offerNetwork is called, the provider can expect to + * immediately receive all requests that can be fulfilled by that offer and + * are not already satisfied by a better network. It is possible no such + * request is currently outstanding, because no requests have been made that + * can be satisfied by this offer, or because all such requests are already + * satisfied by a better network. + * onOfferNeeded can be called at any time after registration and until the + * offer is withdrawn with NetworkProvider#unofferNetwork is called. This + * typically happens when a new network request is filed by an application, + * or when the network satisfying a request disconnects and this offer now + * stands a chance to be the best network for it. + * + * @hide + */ +oneway interface INetworkOfferCallback { + /** + * Informs the registrant that the offer is needed to fulfill this request. + * @param networkRequest the request to satisfy + * @param providerId the ID of the provider currently satisfying + * this request, or NetworkProvider.ID_NONE if none. + */ + void onOfferNeeded(in NetworkRequest networkRequest, int providerId); + + /** + * Informs the registrant that the offer is no longer needed to fulfill this request. + */ + void onOfferUnneeded(in NetworkRequest networkRequest); +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java index c57da53f289d..f65acdd5b467 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java +++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java @@ -879,11 +879,11 @@ public abstract class NetworkAgent { * This method may be called at any time while the network is connected. It has no effect if * the network is already disconnected and the teardown delay timer is running. * - * @param teardownDelayMs the teardown delay to set, or 0 to disable teardown delay. + * @param teardownDelayMillis the teardown delay to set, or 0 to disable teardown delay. */ - public void setTeardownDelayMs( - @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int teardownDelayMs) { - queueOrSendMessage(reg -> reg.sendTeardownDelayMs(teardownDelayMs)); + public void setTeardownDelayMillis( + @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int teardownDelayMillis) { + queueOrSendMessage(reg -> reg.sendTeardownDelayMs(teardownDelayMillis)); } /** diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java index 937a9d23933c..90d821bd3b1e 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java +++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java @@ -139,19 +139,13 @@ public final class NetworkCapabilities implements Parcelable { */ private String mRequestorPackageName; - /** - * Indicates what fields should be redacted from this instance. - */ - private final @RedactionType long mRedactions; - public NetworkCapabilities() { - mRedactions = REDACT_ALL; clearAll(); mNetworkCapabilities = DEFAULT_CAPABILITIES; } public NetworkCapabilities(NetworkCapabilities nc) { - this(nc, REDACT_ALL); + this(nc, REDACT_NONE); } /** @@ -163,10 +157,12 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) { - mRedactions = redactions; if (nc != null) { set(nc); } + if (mTransportInfo != null) { + mTransportInfo = nc.mTransportInfo.makeCopy(redactions); + } } /** @@ -175,15 +171,7 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public void clearAll() { - // Ensures that the internal copies maintained by the connectivity stack does not set it to - // anything other than |REDACT_ALL|. - if (mRedactions != REDACT_ALL) { - // This is needed because the current redaction mechanism relies on redaction while - // parceling. - throw new UnsupportedOperationException( - "Cannot clear NetworkCapabilities when mRedactions is set"); - } - mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0; + mNetworkCapabilities = mTransportTypes = mForbiddenNetworkCapabilities = 0; mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; mNetworkSpecifier = null; mTransportInfo = null; @@ -211,7 +199,7 @@ public final class NetworkCapabilities implements Parcelable { mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; mNetworkSpecifier = nc.mNetworkSpecifier; if (nc.getTransportInfo() != null) { - setTransportInfo(nc.getTransportInfo().makeCopy(mRedactions)); + setTransportInfo(nc.getTransportInfo()); } else { setTransportInfo(null); } @@ -219,7 +207,7 @@ public final class NetworkCapabilities implements Parcelable { mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids); setAdministratorUids(nc.getAdministratorUids()); mOwnerUid = nc.mOwnerUid; - mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities; + mForbiddenNetworkCapabilities = nc.mForbiddenNetworkCapabilities; mSSID = nc.mSSID; mPrivateDnsBroken = nc.mPrivateDnsBroken; mRequestorUid = nc.mRequestorUid; @@ -237,7 +225,7 @@ public final class NetworkCapabilities implements Parcelable { /** * If any capabilities specified here they must not exist in the matching Network. */ - private long mUnwantedNetworkCapabilities; + private long mForbiddenNetworkCapabilities; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -586,21 +574,21 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) { - // If the given capability was previously added to the list of unwanted capabilities - // then the capability will also be removed from the list of unwanted capabilities. - // TODO: Consider adding unwanted capabilities to the public API and mention this + // If the given capability was previously added to the list of forbidden capabilities + // then the capability will also be removed from the list of forbidden capabilities. + // TODO: Consider adding forbidden capabilities to the public API and mention this // in the documentation. checkValidCapability(capability); mNetworkCapabilities |= 1L << capability; - // remove from unwanted capability list - mUnwantedNetworkCapabilities &= ~(1L << capability); + // remove from forbidden capability list + mForbiddenNetworkCapabilities &= ~(1L << capability); return this; } /** - * Adds the given capability to the list of unwanted capabilities of this + * Adds the given capability to the list of forbidden capabilities of this * {@code NetworkCapability} instance. Note that when searching for a network to - * satisfy a request, the network must not contain any capability from unwanted capability + * satisfy a request, the network must not contain any capability from forbidden capability * list. * <p> * If the capability was previously added to the list of required capabilities (for @@ -610,9 +598,9 @@ public final class NetworkCapabilities implements Parcelable { * @see #addCapability(int) * @hide */ - public void addUnwantedCapability(@NetCapability int capability) { + public void addForbiddenCapability(@NetCapability int capability) { checkValidCapability(capability); - mUnwantedNetworkCapabilities |= 1L << capability; + mForbiddenNetworkCapabilities |= 1L << capability; mNetworkCapabilities &= ~(1L << capability); // remove from requested capabilities } @@ -632,16 +620,16 @@ public final class NetworkCapabilities implements Parcelable { } /** - * Removes (if found) the given unwanted capability from this {@code NetworkCapability} - * instance that were added via addUnwantedCapability(int) or setCapabilities(int[], int[]). + * Removes (if found) the given forbidden capability from this {@code NetworkCapability} + * instance that were added via addForbiddenCapability(int) or setCapabilities(int[], int[]). * * @param capability the capability to be removed. * @return This NetworkCapabilities instance, to facilitate chaining. * @hide */ - public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) { + public @NonNull NetworkCapabilities removeForbiddenCapability(@NetCapability int capability) { checkValidCapability(capability); - mUnwantedNetworkCapabilities &= ~(1L << capability); + mForbiddenNetworkCapabilities &= ~(1L << capability); return this; } @@ -670,13 +658,13 @@ public final class NetworkCapabilities implements Parcelable { } /** - * Gets all the unwanted capabilities set on this {@code NetworkCapability} instance. + * Gets all the forbidden capabilities set on this {@code NetworkCapability} instance. * - * @return an array of unwanted capability values for this instance. + * @return an array of forbidden capability values for this instance. * @hide */ - public @NetCapability int[] getUnwantedCapabilities() { - return NetworkCapabilitiesUtils.unpackBits(mUnwantedNetworkCapabilities); + public @NetCapability int[] getForbiddenCapabilities() { + return NetworkCapabilitiesUtils.unpackBits(mForbiddenNetworkCapabilities); } @@ -687,9 +675,9 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public void setCapabilities(@NetCapability int[] capabilities, - @NetCapability int[] unwantedCapabilities) { + @NetCapability int[] forbiddenCapabilities) { mNetworkCapabilities = NetworkCapabilitiesUtils.packBits(capabilities); - mUnwantedNetworkCapabilities = NetworkCapabilitiesUtils.packBits(unwantedCapabilities); + mForbiddenNetworkCapabilities = NetworkCapabilitiesUtils.packBits(forbiddenCapabilities); } /** @@ -714,9 +702,9 @@ public final class NetworkCapabilities implements Parcelable { /** @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public boolean hasUnwantedCapability(@NetCapability int capability) { + public boolean hasForbiddenCapability(@NetCapability int capability) { return isValidCapability(capability) - && ((mUnwantedNetworkCapabilities & (1L << capability)) != 0); + && ((mForbiddenNetworkCapabilities & (1L << capability)) != 0); } /** @@ -746,14 +734,14 @@ public final class NetworkCapabilities implements Parcelable { private void combineNetCapabilities(@NonNull NetworkCapabilities nc) { final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities; - final long unwantedCaps = - this.mUnwantedNetworkCapabilities | nc.mUnwantedNetworkCapabilities; - if ((wantedCaps & unwantedCaps) != 0) { + final long forbiddenCaps = + this.mForbiddenNetworkCapabilities | nc.mForbiddenNetworkCapabilities; + if ((wantedCaps & forbiddenCaps) != 0) { throw new IllegalArgumentException( - "Cannot have the same capability in wanted and unwanted lists."); + "Cannot have the same capability in wanted and forbidden lists."); } this.mNetworkCapabilities = wantedCaps; - this.mUnwantedNetworkCapabilities = unwantedCaps; + this.mForbiddenNetworkCapabilities = forbiddenCaps; } /** @@ -764,7 +752,7 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public @Nullable String describeFirstNonRequestableCapability() { - final long nonRequestable = (mNetworkCapabilities | mUnwantedNetworkCapabilities) + final long nonRequestable = (mNetworkCapabilities | mForbiddenNetworkCapabilities) & NON_REQUESTABLE_CAPABILITIES; if (nonRequestable != 0) { @@ -781,28 +769,28 @@ public final class NetworkCapabilities implements Parcelable { private boolean satisfiedByNetCapabilities(@NonNull NetworkCapabilities nc, boolean onlyImmutable) { long requestedCapabilities = mNetworkCapabilities; - long requestedUnwantedCapabilities = mUnwantedNetworkCapabilities; + long requestedForbiddenCapabilities = mForbiddenNetworkCapabilities; long providedCapabilities = nc.mNetworkCapabilities; if (onlyImmutable) { requestedCapabilities &= ~MUTABLE_CAPABILITIES; - requestedUnwantedCapabilities &= ~MUTABLE_CAPABILITIES; + requestedForbiddenCapabilities &= ~MUTABLE_CAPABILITIES; } return ((providedCapabilities & requestedCapabilities) == requestedCapabilities) - && ((requestedUnwantedCapabilities & providedCapabilities) == 0); + && ((requestedForbiddenCapabilities & providedCapabilities) == 0); } /** @hide */ public boolean equalsNetCapabilities(@NonNull NetworkCapabilities nc) { return (nc.mNetworkCapabilities == this.mNetworkCapabilities) - && (nc.mUnwantedNetworkCapabilities == this.mUnwantedNetworkCapabilities); + && (nc.mForbiddenNetworkCapabilities == this.mForbiddenNetworkCapabilities); } private boolean equalsNetCapabilitiesRequestable(@NonNull NetworkCapabilities that) { - return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) == - (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)) - && ((this.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) == - (that.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)); + return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) + == (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)) + && ((this.mForbiddenNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) + == (that.mForbiddenNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)); } /** @@ -830,8 +818,17 @@ public final class NetworkCapabilities implements Parcelable { final int[] originalAdministratorUids = getAdministratorUids(); final TransportInfo originalTransportInfo = getTransportInfo(); clearAll(); - mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS) - | (1 << TRANSPORT_TEST); + if (0 != (originalCapabilities & NET_CAPABILITY_NOT_RESTRICTED)) { + // If the test network is not restricted, then it is only allowed to declare some + // specific transports. This is to minimize impact on running apps in case an app + // run from the shell creates a test a network. + mTransportTypes = + (originalTransportTypes & UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS) + | (1 << TRANSPORT_TEST); + } else { + // If the test transport is restricted, then it may declare any transport. + mTransportTypes = (originalTransportTypes | (1 << TRANSPORT_TEST)); + } mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES; mNetworkSpecifier = originalSpecifier; mSignalStrength = originalSignalStrength; @@ -935,9 +932,10 @@ public final class NetworkCapabilities implements Parcelable { }; /** - * Allowed transports on a test network, in addition to TRANSPORT_TEST. + * Allowed transports on an unrestricted test network (in addition to TRANSPORT_TEST). */ - private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST + private static final int UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS = + 1 << TRANSPORT_TEST // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces | 1 << TRANSPORT_ETHERNET // Test VPN networks can be created but their UID ranges must be empty. @@ -1718,7 +1716,7 @@ public final class NetworkCapabilities implements Parcelable { * Combine a set of Capabilities to this one. Useful for coming up with the complete set. * <p> * Note that this method may break an invariant of having a particular capability in either - * wanted or unwanted lists but never in both. Requests that have the same capability in + * wanted or forbidden lists but never in both. Requests that have the same capability in * both lists will never be satisfied. * @hide */ @@ -1859,8 +1857,8 @@ public final class NetworkCapabilities implements Parcelable { public int hashCode() { return (int) (mNetworkCapabilities & 0xFFFFFFFF) + ((int) (mNetworkCapabilities >> 32) * 3) - + ((int) (mUnwantedNetworkCapabilities & 0xFFFFFFFF) * 5) - + ((int) (mUnwantedNetworkCapabilities >> 32) * 7) + + ((int) (mForbiddenNetworkCapabilities & 0xFFFFFFFF) * 5) + + ((int) (mForbiddenNetworkCapabilities >> 32) * 7) + ((int) (mTransportTypes & 0xFFFFFFFF) * 11) + ((int) (mTransportTypes >> 32) * 13) + mLinkUpBandwidthKbps * 17 @@ -1895,7 +1893,7 @@ public final class NetworkCapabilities implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(mNetworkCapabilities); - dest.writeLong(mUnwantedNetworkCapabilities); + dest.writeLong(mForbiddenNetworkCapabilities); dest.writeLong(mTransportTypes); dest.writeInt(mLinkUpBandwidthKbps); dest.writeInt(mLinkDownBandwidthKbps); @@ -1919,7 +1917,7 @@ public final class NetworkCapabilities implements Parcelable { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.mNetworkCapabilities = in.readLong(); - netCap.mUnwantedNetworkCapabilities = in.readLong(); + netCap.mForbiddenNetworkCapabilities = in.readLong(); netCap.mTransportTypes = in.readLong(); netCap.mLinkUpBandwidthKbps = in.readInt(); netCap.mLinkDownBandwidthKbps = in.readInt(); @@ -1973,9 +1971,9 @@ public final class NetworkCapabilities implements Parcelable { appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities, NetworkCapabilities::capabilityNameOf, "&"); } - if (0 != mUnwantedNetworkCapabilities) { - sb.append(" Unwanted: "); - appendStringRepresentationOfBitMaskToStringBuilder(sb, mUnwantedNetworkCapabilities, + if (0 != mForbiddenNetworkCapabilities) { + sb.append(" Forbidden: "); + appendStringRepresentationOfBitMaskToStringBuilder(sb, mForbiddenNetworkCapabilities, NetworkCapabilities::capabilityNameOf, "&"); } if (mLinkUpBandwidthKbps > 0) { @@ -2401,6 +2399,11 @@ public final class NetworkCapabilities implements Parcelable { return mTransportInfo.getApplicableRedactions(); } + private NetworkCapabilities removeDefaultCapabilites() { + mNetworkCapabilities &= ~DEFAULT_CAPABILITIES; + return this; + } + /** * Builder class for NetworkCapabilities. * @@ -2437,6 +2440,16 @@ public final class NetworkCapabilities implements Parcelable { } /** + * Creates a new Builder without the default capabilities. + */ + @NonNull + public static Builder withoutDefaultCapabilities() { + final NetworkCapabilities nc = new NetworkCapabilities(); + nc.removeDefaultCapabilites(); + return new Builder(nc); + } + + /** * Adds the given transport type. * * Multiple transports may be added. Note that when searching for a network to satisfy a @@ -2444,7 +2457,8 @@ public final class NetworkCapabilities implements Parcelable { * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network * to be selected. This is logically different than - * {@code NetworkCapabilities.NET_CAPABILITY_*}. + * {@code NetworkCapabilities.NET_CAPABILITY_*}. Also note that multiple networks with the + * same transport type may be active concurrently. * * @param transportType the transport type to be added or removed. * @return this builder @@ -2496,17 +2510,6 @@ public final class NetworkCapabilities implements Parcelable { } /** - * Completely clears the contents of this object, removing even the capabilities that are - * set by default when the object is constructed. - * @return this builder - */ - @NonNull - public Builder clearAll() { - mCaps.clearAll(); - return this; - } - - /** * Sets the owner UID. * * The default value is {@link Process#INVALID_UID}. Pass this value to reset. diff --git a/packages/Connectivity/framework/src/android/net/NetworkProvider.java b/packages/Connectivity/framework/src/android/net/NetworkProvider.java index 14cb51c85d06..8f93047cf850 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkProvider.java +++ b/packages/Connectivity/framework/src/android/net/NetworkProvider.java @@ -28,6 +28,11 @@ import android.os.Message; import android.os.Messenger; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.concurrent.Executor; + /** * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device * to networks and makes them available to the core network stack by creating @@ -78,7 +83,9 @@ public class NetworkProvider { */ @SystemApi public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) { - Handler handler = new Handler(looper) { + // TODO (b/174636568) : this class should be able to cache an instance of + // ConnectivityManager so it doesn't have to fetch it again every time. + final Handler handler = new Handler(looper) { @Override public void handleMessage(Message m) { switch (m.what) { @@ -159,4 +166,148 @@ public class NetworkProvider { public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request); } + + /** @hide */ + // TODO : make @SystemApi when the impl is complete + public interface NetworkOfferCallback { + /** Called by the system when this offer is needed to satisfy some networking request. */ + void onOfferNeeded(@NonNull NetworkRequest request, int providerId); + /** Called by the system when this offer is no longer needed. */ + void onOfferUnneeded(@NonNull NetworkRequest request); + } + + private class NetworkOfferCallbackProxy extends INetworkOfferCallback.Stub { + @NonNull public final NetworkOfferCallback callback; + @NonNull private final Executor mExecutor; + + NetworkOfferCallbackProxy(@NonNull final NetworkOfferCallback callback, + @NonNull final Executor executor) { + this.callback = callback; + this.mExecutor = executor; + } + + @Override + public void onOfferNeeded(final @NonNull NetworkRequest request, + final int providerId) { + mExecutor.execute(() -> callback.onOfferNeeded(request, providerId)); + } + + @Override + public void onOfferUnneeded(final @NonNull NetworkRequest request) { + mExecutor.execute(() -> callback.onOfferUnneeded(request)); + } + } + + @GuardedBy("mProxies") + @NonNull private final ArrayList<NetworkOfferCallbackProxy> mProxies = new ArrayList<>(); + + // Returns the proxy associated with this callback, or null if none. + @Nullable + private NetworkOfferCallbackProxy findProxyForCallback(@NonNull final NetworkOfferCallback cb) { + synchronized (mProxies) { + for (final NetworkOfferCallbackProxy p : mProxies) { + if (p.callback == cb) return p; + } + } + return null; + } + + /** + * Register or update an offer for network with the passed caps and score. + * + * A NetworkProvider's job is to provide networks. This function is how a provider tells the + * connectivity stack what kind of network it may provide. The score and caps arguments act + * as filters that the connectivity stack uses to tell when the offer is necessary. When an + * offer might be advantageous over existing networks, the provider will receive a call to + * the associated callback's {@link NetworkOfferCallback#onOfferNeeded} method. The provider + * should then try to bring up this network. When an offer is no longer needed, the stack + * will inform the provider by calling {@link NetworkOfferCallback#onOfferUnneeded}. The + * provider should stop trying to bring up such a network, or disconnect it if it already has + * one. + * + * The stack determines what offers are needed according to what networks are currently + * available to the system, and what networking requests are made by applications. If an + * offer looks like it could be a better choice than any existing network for any particular + * request, that's when the stack decides the offer is needed. If the current networking + * requests are all satisfied by networks that this offer can't possibly be a better match + * for, that's when the offer is unneeded. An offer starts off as unneeded ; the provider + * should not try to bring up the network until {@link NetworkOfferCallback#onOfferNeeded} + * is called. + * + * Note that the offers are non-binding to the providers, in particular because providers + * often don't know if they will be able to bring up such a network at any given time. For + * example, no wireless network may be in range when the offer is needed. This is fine and + * expected ; the provider should simply continue to try to bring up the network and do so + * if/when it becomes possible. In the mean time, the stack will continue to satisfy requests + * with the best network currently available, or if none, keep the apps informed that no + * network can currently satisfy this request. When/if the provider can bring up the network, + * the connectivity stack will match it against requests, and inform interested apps of the + * availability of this network. This may, in turn, render the offer of some other provider + * unneeded if all requests it used to satisfy are now better served by this network. + * + * A network can become unneeded for a reason like the above : whether the provider managed + * to bring up the offered network after it became needed or not, some other provider may + * bring up a better network than this one, making this offer unneeded. A network may also + * become unneeded if the application making the request withdrew it (for example, after it + * is done transferring data, or if the user canceled an operation). + * + * The capabilities and score act as filters as to what requests the provider will see. + * They are not promises, but for best performance, the providers should strive to put + * as much known information as possible in the offer. For capabilities in particular, it + * should put all NetworkAgent-managed capabilities a network may have, even if it doesn't + * have them at first. This applies to INTERNET, for example ; if a provider thinks the + * network it can bring up for this offer may offer Internet access it should include the + * INTERNET bit. It's fine if the brought up network ends up not actually having INTERNET. + * + * TODO : in the future, to avoid possible infinite loops, there should be constraints on + * what can be put in capabilities of networks brought up for an offer. If a provider might + * bring up a network with or without INTERNET, then it should file two offers : this will + * let it know precisely what networks are needed, so it can avoid bringing up networks that + * won't actually satisfy requests and remove the risk for bring-up-bring-down loops. + * + * @hide + */ + // TODO : make @SystemApi when the impl is complete + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void offerNetwork(@NonNull final NetworkScore score, + @NonNull final NetworkCapabilities caps, @NonNull final Executor executor, + @NonNull final NetworkOfferCallback callback) { + NetworkOfferCallbackProxy proxy = null; + synchronized (mProxies) { + for (final NetworkOfferCallbackProxy existingProxy : mProxies) { + if (existingProxy.callback == callback) { + proxy = existingProxy; + break; + } + } + if (null == proxy) { + proxy = new NetworkOfferCallbackProxy(callback, executor); + mProxies.add(proxy); + } + } + mContext.getSystemService(ConnectivityManager.class).offerNetwork(this, score, caps, proxy); + } + + /** + * Withdraw a network offer previously made to the networking stack. + * + * If a provider can no longer provide a network they offered, it should call this method. + * An example of usage could be if the hardware necessary to bring up the network was turned + * off in UI by the user. Note that because offers are never binding, the provider might + * alternatively decide not to withdraw this offer and simply refuse to bring up the network + * even when it's needed. However, withdrawing the request is slightly more resource-efficient + * because the networking stack won't have to compare this offer to exiting networks to see + * if it could beat any of them, and may be advantageous to the provider's implementation that + * can rely on no longer receiving callbacks for a network that they can't bring up anyways. + * + * @hide + */ + // TODO : make @SystemApi when the impl is complete + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void unofferNetwork(final @NonNull NetworkOfferCallback callback) { + final NetworkOfferCallbackProxy proxy = findProxyForCallback(callback); + if (null == proxy) return; + mProxies.remove(proxy); + mContext.getSystemService(ConnectivityManager.class).unofferNetwork(proxy); + } } diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java index 8c4f4193b50f..dd88c5a5c94e 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java +++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java @@ -311,7 +311,7 @@ public class NetworkRequest implements Parcelable { * * @see #addCapability(int) * - * @param capability The capability to add to unwanted capability list. + * @param capability The capability to add to forbidden capability list. * @return The builder to facilitate chaining. * * @hide @@ -319,15 +319,15 @@ public class NetworkRequest implements Parcelable { @NonNull @SuppressLint("MissingGetterMatchingBuilder") @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) { - mNetworkCapabilities.addUnwantedCapability(capability); + public Builder addForbiddenCapability(@NetworkCapabilities.NetCapability int capability) { + mNetworkCapabilities.addForbiddenCapability(capability); return this; } /** - * Removes (if found) the given unwanted capability from this builder instance. + * Removes (if found) the given forbidden capability from this builder instance. * - * @param capability The unwanted capability to remove. + * @param capability The forbidden capability to remove. * @return The builder to facilitate chaining. * * @hide @@ -335,8 +335,9 @@ public class NetworkRequest implements Parcelable { @NonNull @SuppressLint("BuilderSetStyle") @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public Builder removeUnwantedCapability(@NetworkCapabilities.NetCapability int capability) { - mNetworkCapabilities.removeUnwantedCapability(capability); + public Builder removeForbiddenCapability( + @NetworkCapabilities.NetCapability int capability) { + mNetworkCapabilities.removeForbiddenCapability(capability); return this; } @@ -598,13 +599,13 @@ public class NetworkRequest implements Parcelable { } /** - * @see Builder#addUnwantedCapability(int) + * @see Builder#addForbiddenCapability(int) * * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public boolean hasUnwantedCapability(@NetCapability int capability) { - return networkCapabilities.hasUnwantedCapability(capability); + public boolean hasForbiddenCapability(@NetCapability int capability) { + return networkCapabilities.hasForbiddenCapability(capability); } /** @@ -709,18 +710,18 @@ public class NetworkRequest implements Parcelable { } /** - * Gets all the unwanted capabilities set on this {@code NetworkRequest} instance. + * Gets all the forbidden capabilities set on this {@code NetworkRequest} instance. * - * @return an array of unwanted capability values for this instance. + * @return an array of forbidden capability values for this instance. * * @hide */ @NonNull @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public @NetCapability int[] getUnwantedCapabilities() { - // No need to make a defensive copy here as NC#getUnwantedCapabilities() already returns + public @NetCapability int[] getForbiddenCapabilities() { + // No need to make a defensive copy here as NC#getForbiddenCapabilities() already returns // a new array. - return networkCapabilities.getUnwantedCapabilities(); + return networkCapabilities.getForbiddenCapabilities(); } /** diff --git a/packages/Connectivity/framework/src/android/net/QosFilter.java b/packages/Connectivity/framework/src/android/net/QosFilter.java index ab55002e02b3..957c867f206d 100644 --- a/packages/Connectivity/framework/src/android/net/QosFilter.java +++ b/packages/Connectivity/framework/src/android/net/QosFilter.java @@ -71,5 +71,16 @@ public abstract class QosFilter { */ public abstract boolean matchesLocalAddress(@NonNull InetAddress address, int startPort, int endPort); + + /** + * Determines whether or not the parameters is a match for the filter. + * + * @param address the remote address + * @param startPort the start of the port range + * @param endPort the end of the port range + * @return whether the parameters match the remote address of the filter + */ + public abstract boolean matchesRemoteAddress(@NonNull InetAddress address, + int startPort, int endPort); } diff --git a/packages/Connectivity/framework/src/android/net/QosSocketFilter.java b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java index 2080e68f5fba..69da7f440185 100644 --- a/packages/Connectivity/framework/src/android/net/QosSocketFilter.java +++ b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java @@ -138,13 +138,26 @@ public class QosSocketFilter extends QosFilter { if (mQosSocketInfo.getLocalSocketAddress() == null) { return false; } + return matchesAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort, + endPort); + } - return matchesLocalAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort, + /** + * @inheritDoc + */ + @Override + public boolean matchesRemoteAddress(@NonNull final InetAddress address, final int startPort, + final int endPort) { + if (mQosSocketInfo.getRemoteSocketAddress() == null) { + return false; + } + return matchesAddress(mQosSocketInfo.getRemoteSocketAddress(), address, startPort, endPort); } /** - * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} with the + * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} + * and {@link QosSocketFilter#matchesRemoteAddress(InetAddress, int, int)} with the * filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}. * <p> * This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked @@ -156,7 +169,7 @@ public class QosSocketFilter extends QosFilter { * @param endPort the end of the port range to check */ @VisibleForTesting - public static boolean matchesLocalAddress(@NonNull final InetSocketAddress filterSocketAddress, + public static boolean matchesAddress(@NonNull final InetSocketAddress filterSocketAddress, @NonNull final InetAddress address, final int startPort, final int endPort) { return startPort <= filterSocketAddress.getPort() diff --git a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java index 53d966937a70..a45d5075d6c7 100644 --- a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java +++ b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.ParcelFileDescriptor; @@ -32,7 +33,8 @@ import java.util.Objects; /** * Used in conjunction with * {@link ConnectivityManager#registerQosCallback} - * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}. + * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket} + * and/or remote address and port of a connected {@link Socket}. * * @hide */ @@ -48,6 +50,9 @@ public final class QosSocketInfo implements Parcelable { @NonNull private final InetSocketAddress mLocalSocketAddress; + @Nullable + private final InetSocketAddress mRemoteSocketAddress; + /** * The {@link Network} the socket is on. * @@ -81,6 +86,18 @@ public final class QosSocketInfo implements Parcelable { } /** + * The remote address of the socket passed into {@link QosSocketInfo(Network, Socket)}. + * The value does not reflect any changes that occur to the socket after it is first set + * in the constructor. + * + * @return the remote address of the socket if socket is connected, null otherwise + */ + @Nullable + public InetSocketAddress getRemoteSocketAddress() { + return mRemoteSocketAddress; + } + + /** * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The * {@link Socket} must remain bound in order to receive {@link QosSession}s. * @@ -95,6 +112,12 @@ public final class QosSocketInfo implements Parcelable { mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket); mLocalSocketAddress = new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort()); + + if (socket.isConnected()) { + mRemoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress(); + } else { + mRemoteSocketAddress = null; + } } /* Parcelable methods */ @@ -102,11 +125,15 @@ public final class QosSocketInfo implements Parcelable { mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in)); mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in); - final int addressLength = in.readInt(); - mLocalSocketAddress = readSocketAddress(in, addressLength); + final int localAddressLength = in.readInt(); + mLocalSocketAddress = readSocketAddress(in, localAddressLength); + + final int remoteAddressLength = in.readInt(); + mRemoteSocketAddress = remoteAddressLength == 0 ? null + : readSocketAddress(in, remoteAddressLength); } - private InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) { + private @NonNull InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) { final byte[] address = new byte[addressLength]; in.readByteArray(address); final int port = in.readInt(); @@ -130,10 +157,19 @@ public final class QosSocketInfo implements Parcelable { mNetwork.writeToParcel(dest, 0); mParcelFileDescriptor.writeToParcel(dest, 0); - final byte[] address = mLocalSocketAddress.getAddress().getAddress(); - dest.writeInt(address.length); - dest.writeByteArray(address); + final byte[] localAddress = mLocalSocketAddress.getAddress().getAddress(); + dest.writeInt(localAddress.length); + dest.writeByteArray(localAddress); dest.writeInt(mLocalSocketAddress.getPort()); + + if (mRemoteSocketAddress == null) { + dest.writeInt(0); + } else { + final byte[] remoteAddress = mRemoteSocketAddress.getAddress().getAddress(); + dest.writeInt(remoteAddress.length); + dest.writeByteArray(remoteAddress); + dest.writeInt(mRemoteSocketAddress.getPort()); + } } @NonNull diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java index efd336377114..4071c9ab71b4 100644 --- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java +++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java @@ -40,10 +40,10 @@ import java.util.Objects; @SystemApi(client = MODULE_LIBRARIES) public final class VpnTransportInfo implements TransportInfo, Parcelable { /** Type of this VPN. */ - public final int type; + private final int mType; @Nullable - public final String sessionId; + private final String mSessionId; @Override public @RedactionType long getApplicableRedactions() { @@ -55,13 +55,28 @@ public final class VpnTransportInfo implements TransportInfo, Parcelable { */ @NonNull public VpnTransportInfo makeCopy(@RedactionType long redactions) { - return new VpnTransportInfo(type, - ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : sessionId); + return new VpnTransportInfo(mType, + ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : mSessionId); } public VpnTransportInfo(int type, @Nullable String sessionId) { - this.type = type; - this.sessionId = sessionId; + this.mType = type; + this.mSessionId = sessionId; + } + + /** + * Returns the session Id of this VpnTransportInfo. + */ + @Nullable + public String getSessionId() { + return mSessionId; + } + + /** + * Returns the type of this VPN. + */ + public int getType() { + return mType; } @Override @@ -69,17 +84,17 @@ public final class VpnTransportInfo implements TransportInfo, Parcelable { if (!(o instanceof VpnTransportInfo)) return false; VpnTransportInfo that = (VpnTransportInfo) o; - return (this.type == that.type) && TextUtils.equals(this.sessionId, that.sessionId); + return (this.mType == that.mType) && TextUtils.equals(this.mSessionId, that.mSessionId); } @Override public int hashCode() { - return Objects.hash(type, sessionId); + return Objects.hash(mType, mSessionId); } @Override public String toString() { - return String.format("VpnTransportInfo{type=%d, sessionId=%s}", type, sessionId); + return String.format("VpnTransportInfo{type=%d, sessionId=%s}", mType, mSessionId); } @Override @@ -89,8 +104,8 @@ public final class VpnTransportInfo implements TransportInfo, Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(type); - dest.writeString(sessionId); + dest.writeInt(mType); + dest.writeString(mSessionId); } public static final @NonNull Creator<VpnTransportInfo> CREATOR = diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp index 1330e719e774..513de1956952 100644 --- a/packages/Connectivity/service/Android.bp +++ b/packages/Connectivity/service/Android.bp @@ -52,8 +52,8 @@ cc_library_shared { java_library { name: "service-connectivity-pre-jarjar", srcs: [ + "src/**/*.java", ":framework-connectivity-shared-srcs", - ":connectivity-service-srcs", ], libs: [ "android.net.ipsec.ike", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/packages/Connectivity/service/src/com/android/server/ConnectivityService.java index 88a1917b5d0e..085943a77b5c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/packages/Connectivity/service/src/com/android/server/ConnectivityService.java @@ -15,7 +15,6 @@ */ package com.android.server; - import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.content.pm.PackageManager.FEATURE_BLUETOOTH; import static android.content.pm.PackageManager.FEATURE_WATCH; @@ -34,7 +33,6 @@ import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK; import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN; import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; @@ -54,6 +52,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS; import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL; import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID; @@ -125,6 +124,7 @@ import android.net.INetworkActivityListener; import android.net.INetworkAgent; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; +import android.net.INetworkOfferCallback; import android.net.IOnCompleteListener; import android.net.IQosCallback; import android.net.ISocketKeepaliveCallback; @@ -133,6 +133,8 @@ import android.net.IpMemoryStore; import android.net.IpPrefix; import android.net.LinkProperties; import android.net.MatchAllNetworkSpecifier; +import android.net.NativeNetworkConfig; +import android.net.NativeNetworkType; import android.net.NattSocketKeepalive; import android.net.Network; import android.net.NetworkAgent; @@ -232,6 +234,7 @@ import com.android.net.module.util.PermissionUtils; import com.android.server.connectivity.AutodestructReference; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; +import com.android.server.connectivity.FullScore; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; import com.android.server.connectivity.MockableSystemProperties; @@ -239,6 +242,7 @@ import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.NetworkNotificationManager; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; +import com.android.server.connectivity.NetworkOffer; import com.android.server.connectivity.NetworkRanker; import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.ProfileNetworkPreferences; @@ -602,6 +606,18 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_UID_BLOCKED_REASON_CHANGED = 51; /** + * Event to register a new network offer + * obj = NetworkOffer + */ + private static final int EVENT_REGISTER_NETWORK_OFFER = 52; + + /** + * Event to unregister an existing network offer + * obj = INetworkOfferCallback + */ + private static final int EVENT_UNREGISTER_NETWORK_OFFER = 53; + + /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. */ @@ -1378,7 +1394,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // arguments like the handler or the DnsResolver. // TODO : remove this ; it is probably better handled with a sentinel request. mNoServiceNetwork = new NetworkAgentInfo(null, - new Network(NO_SERVICE_NET_ID), + new Network(INetd.UNREACHABLE_NET_ID), new NetworkInfo(TYPE_NONE, 0, "", ""), new LinkProperties(), new NetworkCapabilities(), new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null, @@ -2176,14 +2192,14 @@ public class ConnectivityService extends IConnectivityManager.Stub PermissionUtils.enforceNetworkStackPermission(mContext); final ArrayList<NetworkState> result = new ArrayList<>(); - for (NetworkStateSnapshot snapshot : getAllNetworkStateSnapshot()) { + for (NetworkStateSnapshot snapshot : getAllNetworkStateSnapshots()) { // NetworkStateSnapshot doesn't contain NetworkInfo, so need to fetch it from the // NetworkAgentInfo. - final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(snapshot.network); + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(snapshot.getNetwork()); if (nai != null && nai.networkInfo.isConnected()) { result.add(new NetworkState(new NetworkInfo(nai.networkInfo), - snapshot.linkProperties, snapshot.networkCapabilities, snapshot.network, - snapshot.subscriberId)); + snapshot.getLinkProperties(), snapshot.getNetworkCapabilities(), + snapshot.getNetwork(), snapshot.getSubscriberId())); } } return result.toArray(new NetworkState[result.size()]); @@ -2191,7 +2207,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override @NonNull - public List<NetworkStateSnapshot> getAllNetworkStateSnapshot() { + public List<NetworkStateSnapshot> getAllNetworkStateSnapshots() { // This contains IMSI details, so make sure the caller is privileged. PermissionUtils.enforceNetworkStackPermission(mContext); @@ -3804,36 +3820,43 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.onNetworkDestroyed(); } - private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) { + private boolean createNativeNetwork(@NonNull NetworkAgentInfo nai) { try { // This should never fail. Specifying an already in use NetID will cause failure. - if (networkAgent.isVPN()) { - mNetd.networkCreateVpn(networkAgent.network.getNetId(), - (networkAgent.networkAgentConfig == null - || !networkAgent.networkAgentConfig.allowBypass)); + final NativeNetworkConfig config; + if (nai.isVPN()) { + if (getVpnType(nai) == VpnManager.TYPE_VPN_NONE) { + Log.wtf(TAG, "Unable to get VPN type from network " + nai.toShortString()); + return false; + } + config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.VIRTUAL, + INetd.PERMISSION_NONE, + (nai.networkAgentConfig == null || !nai.networkAgentConfig.allowBypass), + getVpnType(nai)); } else { - mNetd.networkCreatePhysical(networkAgent.network.getNetId(), - getNetworkPermission(networkAgent.networkCapabilities)); - } - mDnsResolver.createNetworkCache(networkAgent.network.getNetId()); - mDnsManager.updateTransportsForNetwork(networkAgent.network.getNetId(), - networkAgent.networkCapabilities.getTransportTypes()); + config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.PHYSICAL, + getNetworkPermission(nai.networkCapabilities), /*secure=*/ false, + VpnManager.TYPE_VPN_NONE); + } + mNetd.networkCreate(config); + mDnsResolver.createNetworkCache(nai.network.getNetId()); + mDnsManager.updateTransportsForNetwork(nai.network.getNetId(), + nai.networkCapabilities.getTransportTypes()); return true; } catch (RemoteException | ServiceSpecificException e) { - loge("Error creating network " + networkAgent.network.getNetId() + ": " - + e.getMessage()); + loge("Error creating network " + nai.toShortString() + ": " + e.getMessage()); return false; } } - private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) { + private void destroyNativeNetwork(@NonNull NetworkAgentInfo nai) { try { - mNetd.networkDestroy(networkAgent.network.getNetId()); + mNetd.networkDestroy(nai.network.getNetId()); } catch (RemoteException | ServiceSpecificException e) { loge("Exception destroying network(networkDestroy): " + e); } try { - mDnsResolver.destroyNetworkCache(networkAgent.network.getNetId()); + mDnsResolver.destroyNetworkCache(nai.network.getNetId()); } catch (RemoteException | ServiceSpecificException e) { loge("Exception destroying network: " + e); } @@ -4675,6 +4698,18 @@ public class ConnectivityService extends IConnectivityManager.Stub handleUnregisterNetworkProvider((Messenger) msg.obj); break; } + case EVENT_REGISTER_NETWORK_OFFER: { + handleRegisterNetworkOffer((NetworkOffer) msg.obj); + break; + } + case EVENT_UNREGISTER_NETWORK_OFFER: { + final NetworkOfferInfo offer = + findNetworkOfferInfoByCallback((INetworkOfferCallback) msg.obj); + if (null != offer) { + handleUnregisterNetworkOffer(offer); + } + break; + } case EVENT_REGISTER_NETWORK_AGENT: { final Pair<NetworkAgentInfo, INetworkMonitor> arg = (Pair<NetworkAgentInfo, INetworkMonitor>) msg.obj; @@ -4769,6 +4804,7 @@ public class ConnectivityService extends IConnectivityManager.Stub (Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener>) msg.obj; handleSetProfileNetworkPreference(arg.first, arg.second); + break; } case EVENT_REPORT_NETWORK_ACTIVITY: mNetworkActivityTracker.handleReportNetworkActivity(); @@ -6204,12 +6240,37 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_PROVIDER, messenger)); } + @Override + public void offerNetwork(@NonNull final Messenger providerMessenger, + @NonNull final NetworkScore score, @NonNull final NetworkCapabilities caps, + @NonNull final INetworkOfferCallback callback) { + final NetworkOffer offer = new NetworkOffer( + FullScore.makeProspectiveScore(score, caps), caps, callback, providerMessenger); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_OFFER, offer)); + } + + @Override + public void unofferNetwork(@NonNull final INetworkOfferCallback callback) { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_OFFER, callback)); + } + private void handleUnregisterNetworkProvider(Messenger messenger) { NetworkProviderInfo npi = mNetworkProviderInfos.remove(messenger); if (npi == null) { loge("Failed to find Messenger in unregisterNetworkProvider"); return; } + // Unregister all the offers from this provider + final ArrayList<NetworkOfferInfo> toRemove = new ArrayList<>(); + for (final NetworkOfferInfo noi : mNetworkOffers) { + if (noi.offer.provider == messenger) { + // Can't call handleUnregisterNetworkOffer here because iteration is in progress + toRemove.add(noi); + } + } + for (NetworkOfferInfo noi : toRemove) { + handleUnregisterNetworkOffer(noi); + } if (DBG) log("unregisterNetworkProvider for " + npi.name); } @@ -6248,6 +6309,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // (on the handler thread). private volatile List<UidRange> mVpnBlockedUidRanges = new ArrayList<>(); + // Must only be accessed on the handler thread + @NonNull + private final ArrayList<NetworkOfferInfo> mNetworkOffers = new ArrayList<>(); + @GuardedBy("mBlockedAppUids") private final HashSet<Integer> mBlockedAppUids = new HashSet<>(); @@ -6423,8 +6488,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // Request used to optionally keep vehicle internal network always active private final NetworkRequest mDefaultVehicleRequest; - // TODO replace with INetd.UNREACHABLE_NET_ID when available. - private static final int NO_SERVICE_NET_ID = 52; // Sentinel NAI used to direct apps with default networks that should have no connectivity to a // network with no service. This NAI should never be matched against, nor should any public API // ever return the associated network. For this reason, this NAI is not in the list of available @@ -6572,6 +6635,65 @@ public class ConnectivityService extends IConnectivityManager.Stub updateUids(nai, null, nai.networkCapabilities); } + private class NetworkOfferInfo implements IBinder.DeathRecipient { + @NonNull public final NetworkOffer offer; + + NetworkOfferInfo(@NonNull final NetworkOffer offer) { + this.offer = offer; + } + + @Override + public void binderDied() { + mHandler.post(() -> handleUnregisterNetworkOffer(this)); + } + } + + /** + * Register or update a network offer. + * @param newOffer The new offer. If the callback member is the same as an existing + * offer, it is an update of that offer. + */ + private void handleRegisterNetworkOffer(@NonNull final NetworkOffer newOffer) { + ensureRunningOnConnectivityServiceThread(); + if (null == mNetworkProviderInfos.get(newOffer.provider)) { + // This may actually happen if a provider updates its score or registers and then + // immediately unregisters. The offer would still be in the handler queue, but the + // provider would have been removed. + if (DBG) log("Received offer from an unregistered provider"); + return; + } + + final NetworkOfferInfo existingOffer = findNetworkOfferInfoByCallback(newOffer.callback); + if (null != existingOffer) { + handleUnregisterNetworkOffer(existingOffer); + newOffer.migrateFrom(existingOffer.offer); + } + final NetworkOfferInfo noi = new NetworkOfferInfo(newOffer); + try { + noi.offer.provider.getBinder().linkToDeath(noi, 0 /* flags */); + } catch (RemoteException e) { + noi.binderDied(); + return; + } + mNetworkOffers.add(noi); + // TODO : send requests to the provider. + } + + private void handleUnregisterNetworkOffer(@NonNull final NetworkOfferInfo noi) { + ensureRunningOnConnectivityServiceThread(); + mNetworkOffers.remove(noi); + noi.offer.provider.getBinder().unlinkToDeath(noi, 0 /* flags */); + } + + @Nullable private NetworkOfferInfo findNetworkOfferInfoByCallback( + @NonNull final INetworkOfferCallback callback) { + ensureRunningOnConnectivityServiceThread(); + for (final NetworkOfferInfo noi : mNetworkOffers) { + if (noi.offer.callback.equals(callback)) return noi; + } + return null; + } + /** * Called when receiving LinkProperties directly from a NetworkAgent. * Stores into |nai| any data coming from the agent that might also be written to the network's @@ -8466,11 +8588,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo(); try { final ArrayList<NetworkStateSnapshot> snapshots = new ArrayList<>(); - // TODO: Directly use NetworkStateSnapshot when feasible. - for (final NetworkState state : getAllNetworkState()) { - final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network, - state.networkCapabilities, state.linkProperties, state.subscriberId, - state.legacyNetworkType); + for (final NetworkStateSnapshot snapshot : getAllNetworkStateSnapshots()) { snapshots.add(snapshot); } mStatsManager.notifyNetworkStatus(getDefaultNetworks(), @@ -8571,8 +8689,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // restore private DNS settings to default mode (opportunistic) if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) { - Settings.Global.putString(mContext.getContentResolver(), - ConnectivitySettingsManager.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC); + ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OPPORTUNISTIC); } Settings.Global.putString(mContext.getContentResolver(), @@ -8664,7 +8781,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (vpn == null) return VpnManager.TYPE_VPN_NONE; final TransportInfo ti = vpn.networkCapabilities.getTransportInfo(); if (!(ti instanceof VpnTransportInfo)) return VpnManager.TYPE_VPN_NONE; - return ((VpnTransportInfo) ti).type; + return ((VpnTransportInfo) ti).getType(); } /** @@ -9032,7 +9149,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } private NetworkCapabilities getNetworkCapabilitiesWithoutUids(@NonNull NetworkCapabilities nc) { - final NetworkCapabilities sanitized = new NetworkCapabilities(nc); + final NetworkCapabilities sanitized = new NetworkCapabilities(nc, + NetworkCapabilities.REDACT_ALL); sanitized.setUids(null); sanitized.setAdministratorUids(new int[0]); sanitized.setOwnerUid(Process.INVALID_UID); @@ -9593,7 +9711,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // request. final ArrayList<NetworkRequest> nrs = new ArrayList<>(); nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities)); - nrs.add(createDefaultRequest()); + nrs.add(createDefaultInternetRequestForTransport( + TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT)); setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids())); final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs); result.add(nri); @@ -9898,7 +10017,8 @@ public class ConnectivityService extends IConnectivityManager.Stub case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID: requests.add(createUnmeteredNetworkRequest()); requests.add(createOemPaidNetworkRequest()); - requests.add(createDefaultRequest()); + requests.add(createDefaultInternetRequestForTransport( + TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT)); break; case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK: requests.add(createUnmeteredNetworkRequest()); diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/packages/Connectivity/service/src/com/android/server/ConnectivityServiceInitializer.java index 2465479aadd8..2465479aadd8 100644 --- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java +++ b/packages/Connectivity/service/src/com/android/server/ConnectivityServiceInitializer.java diff --git a/services/core/java/com/android/server/NetIdManager.java b/packages/Connectivity/service/src/com/android/server/NetIdManager.java index 61925c80a22b..61925c80a22b 100644 --- a/services/core/java/com/android/server/NetIdManager.java +++ b/packages/Connectivity/service/src/com/android/server/NetIdManager.java diff --git a/services/core/java/com/android/server/TestNetworkService.java b/packages/Connectivity/service/src/com/android/server/TestNetworkService.java index f5662772f59f..f5662772f59f 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/packages/Connectivity/service/src/com/android/server/TestNetworkService.java diff --git a/services/core/java/com/android/server/connectivity/AutodestructReference.java b/packages/Connectivity/service/src/com/android/server/connectivity/AutodestructReference.java index 009a43e58285..009a43e58285 100644 --- a/services/core/java/com/android/server/connectivity/AutodestructReference.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/AutodestructReference.java diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/packages/Connectivity/service/src/com/android/server/connectivity/ConnectivityConstants.java index 325a2cd7bd69..325a2cd7bd69 100644 --- a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/ConnectivityConstants.java diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/packages/Connectivity/service/src/com/android/server/connectivity/DnsManager.java index cf4fe1ef9f97..05b12bad5589 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/DnsManager.java @@ -16,14 +16,14 @@ package com.android.server.connectivity; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES; import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES; import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS; import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS; @@ -33,6 +33,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; +import android.net.ConnectivitySettingsManager; import android.net.IDnsResolver; import android.net.InetAddresses; import android.net.LinkProperties; @@ -131,11 +132,11 @@ public class DnsManager { * Get PrivateDnsConfig. */ public static PrivateDnsConfig getPrivateDnsConfig(Context context) { - final String mode = ConnectivityManager.getPrivateDnsMode(context); + final int mode = ConnectivitySettingsManager.getPrivateDnsMode(context); - final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode); + final boolean useTls = mode != PRIVATE_DNS_MODE_OFF; - if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) { + if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME == mode) { final String specifier = getStringSetting(context.getContentResolver(), PRIVATE_DNS_SPECIFIER); return new PrivateDnsConfig(specifier, null); diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/packages/Connectivity/service/src/com/android/server/connectivity/FullScore.java index 028cfee36593..9326d692f6e4 100644 --- a/services/core/java/com/android/server/connectivity/FullScore.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/FullScore.java @@ -16,6 +16,7 @@ package com.android.server.connectivity; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_VPN; @@ -116,6 +117,33 @@ public class FullScore { } /** + * Given a score supplied by the NetworkAgent, produce a prospective score for an offer. + * + * NetworkOffers have score filters that are compared to the scores of actual networks + * to see if they could possibly beat the current satisfier. Some things the agent can't + * know in advance ; a good example is the validation bit – some networks will validate, + * others won't. For comparison purposes, assume the best, so all possibly beneficial + * networks will be brought up. + * + * @param score the score supplied by the agent for this offer + * @param caps the capabilities supplied by the agent for this offer + * @return a FullScore appropriate for comparing to actual network's scores. + */ + public static FullScore makeProspectiveScore(@NonNull final NetworkScore score, + @NonNull final NetworkCapabilities caps) { + // If the network offers Internet access, it may validate. + final boolean mayValidate = caps.hasCapability(NET_CAPABILITY_INTERNET); + // VPN transports are known in advance. + final boolean vpn = caps.hasTransport(TRANSPORT_VPN); + // The network hasn't been chosen by the user (yet, at least). + final boolean everUserSelected = false; + // Don't assume the user will accept unvalidated connectivity. + final boolean acceptUnvalidated = false; + return withPolicies(score.getLegacyInt(), mayValidate, vpn, everUserSelected, + acceptUnvalidated); + } + + /** * Return a new score given updated caps and config. * * @param caps the NetworkCapabilities of the network diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/packages/Connectivity/service/src/com/android/server/connectivity/KeepaliveTracker.java index acf39f05a541..acf39f05a541 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/KeepaliveTracker.java diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/packages/Connectivity/service/src/com/android/server/connectivity/LingerMonitor.java index 032612c6f093..032612c6f093 100644 --- a/services/core/java/com/android/server/connectivity/LingerMonitor.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/LingerMonitor.java diff --git a/services/core/java/com/android/server/connectivity/MockableSystemProperties.java b/packages/Connectivity/service/src/com/android/server/connectivity/MockableSystemProperties.java index a25b89ac039a..a25b89ac039a 100644 --- a/services/core/java/com/android/server/connectivity/MockableSystemProperties.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/MockableSystemProperties.java diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/packages/Connectivity/service/src/com/android/server/connectivity/Nat464Xlat.java index c66a280f2b02..c66a280f2b02 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/Nat464Xlat.java diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkAgentInfo.java index ee32fbf00dfe..ee32fbf00dfe 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkAgentInfo.java diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkDiagnostics.java index 2e51be39bfae..2e51be39bfae 100644 --- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkDiagnostics.java diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkNotificationManager.java index 0c0d45995a2b..0c0d45995a2b 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkNotificationManager.java diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkOffer.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkOffer.java new file mode 100644 index 000000000000..fa2d465fff1d --- /dev/null +++ b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkOffer.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.INetworkOfferCallback; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Messenger; + +import java.util.Objects; + + +/** + * Represents an offer made by a NetworkProvider to create a network if a need arises. + * + * This class contains the prospective score and capabilities of the network. The provider + * is not obligated to caps able to create a network satisfying this, nor to build a network + * with the exact score and/or capabilities passed ; after all, not all providers know in + * advance what a network will look like after it's connected. Instead, this is meant as a + * filter to limit requests sent to the provider by connectivity to those that this offer stands + * a chance to fulfill. + * + * @see NetworkProvider#offerNetwork. + * + * @hide + */ +public class NetworkOffer { + @NonNull public final FullScore score; + @NonNull public final NetworkCapabilities caps; + @NonNull public final INetworkOfferCallback callback; + @NonNull public final Messenger provider; + + private static NetworkCapabilities emptyCaps() { + final NetworkCapabilities nc = new NetworkCapabilities(); + return nc; + } + + // Ideally the caps argument would be non-null, but null has historically meant no filter + // and telephony passes null. Keep backward compatibility. + public NetworkOffer(@NonNull final FullScore score, + @Nullable final NetworkCapabilities caps, + @NonNull final INetworkOfferCallback callback, + @NonNull final Messenger provider) { + this.score = Objects.requireNonNull(score); + this.caps = null != caps ? caps : emptyCaps(); + this.callback = Objects.requireNonNull(callback); + this.provider = Objects.requireNonNull(provider); + } + + /** + * Migrate from, and take over, a previous offer. + * + * When an updated offer is sent from a provider, call this method on the new offer, passing + * the old one, to take over the state. + * + * @param previousOffer + */ + public void migrateFrom(@NonNull final NetworkOffer previousOffer) { + if (!callback.equals(previousOffer.callback)) { + throw new IllegalArgumentException("Can only migrate from a previous version of" + + " the same offer"); + } + } + + /** + * Returns whether an offer can satisfy a NetworkRequest, according to its capabilities. + * @param request The request to test against. + * @return Whether this offer can satisfy the request. + */ + public final boolean canSatisfy(@NonNull final NetworkRequest request) { + return request.networkCapabilities.satisfiedByNetworkCapabilities(caps); + } + + @Override + public String toString() { + return "NetworkOffer [ Score " + score + " ]"; + } +} diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java index d0aabf95d572..d0aabf95d572 100644 --- a/services/core/java/com/android/server/connectivity/NetworkRanker.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/packages/Connectivity/service/src/com/android/server/connectivity/PermissionMonitor.java index 7837e6e812f8..673c80417b8d 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/PermissionMonitor.java @@ -24,6 +24,7 @@ import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; +import static android.net.ConnectivitySettingsManager.APPS_ALLOWED_ON_RESTRICTED_NETWORKS; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; @@ -39,6 +40,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.database.ContentObserver; +import android.net.ConnectivitySettingsManager; import android.net.INetd; import android.net.UidRange; import android.net.Uri; @@ -48,7 +51,9 @@ import android.os.ServiceSpecificException; import android.os.SystemConfigManager; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.system.OsConstants; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; @@ -66,7 +71,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; - /** * A utility class to inform Netd of UID permisisons. * Does a mass update at boot and then monitors for app install/remove. @@ -105,6 +109,14 @@ public class PermissionMonitor { @GuardedBy("this") private final Set<Integer> mAllApps = new HashSet<>(); + // A set of apps which are allowed to use restricted networks. These apps can't hold the + // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be signature|privileged + // apps. However, these apps should still be able to use restricted networks under certain + // conditions (e.g. government app using emergency services). So grant netd system permission + // to uids whose package name is listed in APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting. + @GuardedBy("this") + private final Set<String> mAppsAllowedOnRestrictedNetworks = new ArraySet<>(); + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -135,6 +147,22 @@ public class PermissionMonitor { public int getDeviceFirstSdkInt() { return Build.VERSION.FIRST_SDK_INT; } + + /** + * Get apps allowed to use restricted networks via ConnectivitySettingsManager. + */ + public Set<String> getAppsAllowedOnRestrictedNetworks(@NonNull Context context) { + return ConnectivitySettingsManager.getAppsAllowedOnRestrictedNetworks(context); + } + + /** + * Register ContentObserver for given Uri. + */ + public void registerContentObserver(@NonNull Context context, @NonNull Uri uri, + boolean notifyForDescendants, @NonNull ContentObserver observer) { + context.getContentResolver().registerContentObserver( + uri, notifyForDescendants, observer); + } } public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) { @@ -157,14 +185,31 @@ public class PermissionMonitor { public synchronized void startMonitoring() { log("Monitoring"); + final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); - mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */).registerReceiver( + userAllContext.registerReceiver( mIntentReceiver, intentFilter, null /* broadcastPermission */, null /* scheduler */); + // Register APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer + mDeps.registerContentObserver( + userAllContext, + Settings.Secure.getUriFor(APPS_ALLOWED_ON_RESTRICTED_NETWORKS), + false /* notifyForDescendants */, + new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + onSettingChanged(); + } + }); + + // Read APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update + // mAppsAllowedOnRestrictedNetworks. + updateAppsAllowedOnRestrictedNetworks(mDeps.getAppsAllowedOnRestrictedNetworks(mContext)); + List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS | MATCH_ANY_USER); if (apps == null) { @@ -220,11 +265,33 @@ public class PermissionMonitor { } @VisibleForTesting + void updateAppsAllowedOnRestrictedNetworks(final Set<String> apps) { + mAppsAllowedOnRestrictedNetworks.clear(); + mAppsAllowedOnRestrictedNetworks.addAll(apps); + } + + @VisibleForTesting static boolean isVendorApp(@NonNull ApplicationInfo appInfo) { return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct(); } @VisibleForTesting + boolean isCarryoverPackage(final ApplicationInfo appInfo) { + if (appInfo == null) return false; + return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo)) + // Backward compatibility for b/114245686, on devices that launched before Q daemons + // and apps running as the system UID are exempted from this check. + || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q); + } + + @VisibleForTesting + boolean isAppAllowedOnRestrictedNetworks(@NonNull final PackageInfo app) { + // Check whether package name is in allowed on restricted networks app list. If so, this app + // can have netd system permission. + return mAppsAllowedOnRestrictedNetworks.contains(app.packageName); + } + + @VisibleForTesting boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) { if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) { return false; @@ -241,22 +308,10 @@ public class PermissionMonitor { @VisibleForTesting boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) { - // TODO : remove this check in the future(b/31479477). All apps should just - // request the appropriate permission for their use case since android Q. - if (app.applicationInfo != null) { - // Backward compatibility for b/114245686, on devices that launched before Q daemons - // and apps running as the system UID are exempted from this check. - if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) { - return true; - } - - if (app.applicationInfo.targetSdkVersion < VERSION_Q - && isVendorApp(app.applicationInfo)) { - return true; - } - } - - return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK) + // TODO : remove carryover package check in the future(b/31479477). All apps should just + // request the appropriate permission for their use case since android Q. + return isCarryoverPackage(app.applicationInfo) || isAppAllowedOnRestrictedNetworks(app) + || hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK) || hasPermission(app, NETWORK_STACK) || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS); } @@ -338,7 +393,8 @@ public class PermissionMonitor { return currentPermission; } try { - final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS); + final PackageInfo app = mPackageManager.getPackageInfo(name, + GET_PERMISSIONS | MATCH_ANY_USER); final boolean isNetwork = hasNetworkPermission(app); final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app); if (isNetwork || hasRestrictedPermission) { @@ -409,6 +465,20 @@ public class PermissionMonitor { mAllApps.add(UserHandle.getAppId(uid)); } + private Boolean highestUidNetworkPermission(int uid) { + Boolean permission = null; + final String[] packages = mPackageManager.getPackagesForUid(uid); + if (!CollectionUtils.isEmpty(packages)) { + for (String name : packages) { + permission = highestPermissionForUid(permission, name); + if (permission == SYSTEM) { + break; + } + } + } + return permission; + } + /** * Called when a package is removed. * @@ -439,19 +509,14 @@ public class PermissionMonitor { } Map<Integer, Boolean> apps = new HashMap<>(); - Boolean permission = null; - String[] packages = mPackageManager.getPackagesForUid(uid); - if (packages != null && packages.length > 0) { - for (String name : packages) { - permission = highestPermissionForUid(permission, name); - if (permission == SYSTEM) { - // An app with this UID still has the SYSTEM permission. - // Therefore, this UID must already have the SYSTEM permission. - // Nothing to do. - return; - } - } + final Boolean permission = highestUidNetworkPermission(uid); + if (permission == SYSTEM) { + // An app with this UID still has the SYSTEM permission. + // Therefore, this UID must already have the SYSTEM permission. + // Nothing to do. + return; } + if (permission == mApps.get(uid)) { // The permissions of this UID have not changed. Nothing to do. return; @@ -664,6 +729,7 @@ public class PermissionMonitor { break; case INetd.PERMISSION_UNINSTALLED: uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i)); + break; default: Log.e(TAG, "unknown permission type: " + permissions + "for uid: " + netdPermissionsAppIds.keyAt(i)); @@ -703,6 +769,38 @@ public class PermissionMonitor { return mVpnUidRanges.get(iface); } + private synchronized void onSettingChanged() { + // Step1. Update apps allowed to use restricted networks and compute the set of packages to + // update. + final Set<String> packagesToUpdate = new ArraySet<>(mAppsAllowedOnRestrictedNetworks); + updateAppsAllowedOnRestrictedNetworks(mDeps.getAppsAllowedOnRestrictedNetworks(mContext)); + packagesToUpdate.addAll(mAppsAllowedOnRestrictedNetworks); + + final Map<Integer, Boolean> updatedApps = new HashMap<>(); + final Map<Integer, Boolean> removedApps = new HashMap<>(); + + // Step2. For each package to update, find out its new permission. + for (String app : packagesToUpdate) { + final PackageInfo info = getPackageInfo(app); + if (info == null || info.applicationInfo == null) continue; + + final int uid = info.applicationInfo.uid; + final Boolean permission = highestUidNetworkPermission(uid); + + if (null == permission) { + removedApps.put(uid, NETWORK); // Doesn't matter which permission is set here. + mApps.remove(uid); + } else { + updatedApps.put(uid, permission); + mApps.put(uid, permission); + } + } + + // Step3. Update or revoke permission for uids with netd. + update(mUsers, updatedApps, true /* add */); + update(mUsers, removedApps, false /* add */); + } + /** Dump info to dumpsys */ public void dump(IndentingPrintWriter pw) { pw.println("Interface filtering rules:"); diff --git a/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java b/packages/Connectivity/service/src/com/android/server/connectivity/ProfileNetworkPreferences.java index dd2815d9e2e3..dd2815d9e2e3 100644 --- a/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/ProfileNetworkPreferences.java diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/packages/Connectivity/service/src/com/android/server/connectivity/ProxyTracker.java index f572b46a9b58..f572b46a9b58 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/ProxyTracker.java diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java index 534dbe7699a7..534dbe7699a7 100644 --- a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackTracker.java index b6ab47b276e3..b6ab47b276e3 100644 --- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackTracker.java diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/packages/Connectivity/service/src/com/android/server/connectivity/TcpKeepaliveController.java index c480594b8c60..c480594b8c60 100644 --- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java +++ b/packages/Connectivity/service/src/com/android/server/connectivity/TcpKeepaliveController.java diff --git a/tests/net/OWNERS b/packages/Connectivity/tests/OWNERS index d3836d4c6c57..d3836d4c6c57 100644 --- a/tests/net/OWNERS +++ b/packages/Connectivity/tests/OWNERS diff --git a/tests/net/TEST_MAPPING b/packages/Connectivity/tests/TEST_MAPPING index 502f885ceb78..502f885ceb78 100644 --- a/tests/net/TEST_MAPPING +++ b/packages/Connectivity/tests/TEST_MAPPING diff --git a/tests/net/common/Android.bp b/packages/Connectivity/tests/common/Android.bp index babb81c5fa34..babb81c5fa34 100644 --- a/tests/net/common/Android.bp +++ b/packages/Connectivity/tests/common/Android.bp diff --git a/tests/net/common/java/ParseExceptionTest.kt b/packages/Connectivity/tests/common/java/ParseExceptionTest.kt index b702d61a9fe1..b702d61a9fe1 100644 --- a/tests/net/common/java/ParseExceptionTest.kt +++ b/packages/Connectivity/tests/common/java/ParseExceptionTest.kt diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/packages/Connectivity/tests/common/java/android/net/CaptivePortalDataTest.kt index 18a93319b271..18a93319b271 100644 --- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/CaptivePortalDataTest.kt diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/packages/Connectivity/tests/common/java/android/net/CaptivePortalTest.java index 15d3398d43c0..15d3398d43c0 100644 --- a/tests/net/common/java/android/net/CaptivePortalTest.java +++ b/packages/Connectivity/tests/common/java/android/net/CaptivePortalTest.java diff --git a/tests/net/common/java/android/net/DependenciesTest.java b/packages/Connectivity/tests/common/java/android/net/DependenciesTest.java index ac1c28a45462..ac1c28a45462 100644 --- a/tests/net/common/java/android/net/DependenciesTest.java +++ b/packages/Connectivity/tests/common/java/android/net/DependenciesTest.java diff --git a/tests/net/common/java/android/net/DhcpInfoTest.java b/packages/Connectivity/tests/common/java/android/net/DhcpInfoTest.java index ab4726bab573..ab4726bab573 100644 --- a/tests/net/common/java/android/net/DhcpInfoTest.java +++ b/packages/Connectivity/tests/common/java/android/net/DhcpInfoTest.java diff --git a/tests/net/common/java/android/net/IpPrefixTest.java b/packages/Connectivity/tests/common/java/android/net/IpPrefixTest.java index 50ecb428359e..50ecb428359e 100644 --- a/tests/net/common/java/android/net/IpPrefixTest.java +++ b/packages/Connectivity/tests/common/java/android/net/IpPrefixTest.java diff --git a/tests/net/common/java/android/net/KeepalivePacketDataTest.kt b/packages/Connectivity/tests/common/java/android/net/KeepalivePacketDataTest.kt index f464ec6cf0e5..f464ec6cf0e5 100644 --- a/tests/net/common/java/android/net/KeepalivePacketDataTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/KeepalivePacketDataTest.kt diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/packages/Connectivity/tests/common/java/android/net/LinkAddressTest.java index 2cf3cf9c11da..2cf3cf9c11da 100644 --- a/tests/net/common/java/android/net/LinkAddressTest.java +++ b/packages/Connectivity/tests/common/java/android/net/LinkAddressTest.java diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/packages/Connectivity/tests/common/java/android/net/LinkPropertiesTest.java index 550953d0612d..550953d0612d 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/packages/Connectivity/tests/common/java/android/net/LinkPropertiesTest.java diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/packages/Connectivity/tests/common/java/android/net/MatchAllNetworkSpecifierTest.kt index a5e44d59fcab..a5e44d59fcab 100644 --- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/MatchAllNetworkSpecifierTest.kt diff --git a/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt b/packages/Connectivity/tests/common/java/android/net/NattKeepalivePacketDataTest.kt index 46f39dd016fd..46f39dd016fd 100644 --- a/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/NattKeepalivePacketDataTest.kt diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/packages/Connectivity/tests/common/java/android/net/NetworkAgentConfigTest.kt index 2b45b3d69ce9..2b45b3d69ce9 100644 --- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/NetworkAgentConfigTest.kt diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/packages/Connectivity/tests/common/java/android/net/NetworkCapabilitiesTest.java index 33f2c67646e5..d74b802c8729 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/packages/Connectivity/tests/common/java/android/net/NetworkCapabilitiesTest.java @@ -340,7 +340,7 @@ public class NetworkCapabilitiesTest { private void testParcelSane(NetworkCapabilities cap) { if (isAtLeastS()) { - assertParcelSane(cap, 17); + assertParcelSane(cap, 16); } else if (isAtLeastR()) { assertParcelSane(cap, 15); } else { @@ -390,9 +390,11 @@ public class NetworkCapabilitiesTest { @Test public void testOemPaid() { NetworkCapabilities nc = new NetworkCapabilities(); - // By default OEM_PAID is neither in the unwanted or required lists and the network is not + // By default OEM_PAID is neither in the required or forbidden lists and the network is not // restricted. - assertFalse(nc.hasUnwantedCapability(NET_CAPABILITY_OEM_PAID)); + if (isAtLeastS()) { + assertFalse(nc.hasForbiddenCapability(NET_CAPABILITY_OEM_PAID)); + } assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PAID)); nc.maybeMarkCapabilitiesRestricted(); assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); @@ -417,9 +419,9 @@ public class NetworkCapabilitiesTest { @Test @IgnoreUpTo(Build.VERSION_CODES.R) public void testOemPrivate() { NetworkCapabilities nc = new NetworkCapabilities(); - // By default OEM_PRIVATE is neither in the unwanted or required lists and the network is + // By default OEM_PRIVATE is neither in the required or forbidden lists and the network is // not restricted. - assertFalse(nc.hasUnwantedCapability(NET_CAPABILITY_OEM_PRIVATE)); + assertFalse(nc.hasForbiddenCapability(NET_CAPABILITY_OEM_PRIVATE)); assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PRIVATE)); nc.maybeMarkCapabilitiesRestricted(); assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); @@ -441,8 +443,8 @@ public class NetworkCapabilitiesTest { assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities())); } - @Test - public void testUnwantedCapabilities() { + @Test @IgnoreUpTo(Build.VERSION_CODES.R) + public void testForbiddenCapabilities() { NetworkCapabilities network = new NetworkCapabilities(); NetworkCapabilities request = new NetworkCapabilities(); @@ -450,19 +452,19 @@ public class NetworkCapabilitiesTest { request.satisfiedByNetworkCapabilities(network)); // Requesting absence of capabilities that network doesn't have. Request should satisfy. - request.addUnwantedCapability(NET_CAPABILITY_WIFI_P2P); - request.addUnwantedCapability(NET_CAPABILITY_NOT_METERED); + request.addForbiddenCapability(NET_CAPABILITY_WIFI_P2P); + request.addForbiddenCapability(NET_CAPABILITY_NOT_METERED); assertTrue(request.satisfiedByNetworkCapabilities(network)); - assertArrayEquals(new int[] {NET_CAPABILITY_WIFI_P2P, + assertArrayEquals(new int[]{NET_CAPABILITY_WIFI_P2P, NET_CAPABILITY_NOT_METERED}, - request.getUnwantedCapabilities()); + request.getForbiddenCapabilities()); // This is a default capability, just want to make sure its there because we use it below. assertTrue(network.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); - // Verify that adding unwanted capability will effectively remove it from capability list. - request.addUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED); - assertTrue(request.hasUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED)); + // Verify that adding forbidden capability will effectively remove it from capability list. + request.addForbiddenCapability(NET_CAPABILITY_NOT_RESTRICTED); + assertTrue(request.hasForbiddenCapability(NET_CAPABILITY_NOT_RESTRICTED)); assertFalse(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); // Now this request won't be satisfied because network contains NOT_RESTRICTED. @@ -470,10 +472,10 @@ public class NetworkCapabilitiesTest { network.removeCapability(NET_CAPABILITY_NOT_RESTRICTED); assertTrue(request.satisfiedByNetworkCapabilities(network)); - // Verify that adding capability will effectively remove it from unwanted list + // Verify that adding capability will effectively remove it from forbidden list request.addCapability(NET_CAPABILITY_NOT_RESTRICTED); assertTrue(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); - assertFalse(request.hasUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED)); + assertFalse(request.hasForbiddenCapability(NET_CAPABILITY_NOT_RESTRICTED)); assertFalse(request.satisfiedByNetworkCapabilities(network)); network.addCapability(NET_CAPABILITY_NOT_RESTRICTED); @@ -512,24 +514,20 @@ public class NetworkCapabilitiesTest { assertTrue(nc1.equalsNetCapabilities(nc2)); assertEquals(nc1, nc2); - nc1.addUnwantedCapability(NET_CAPABILITY_INTERNET); - assertFalse(nc1.equalsNetCapabilities(nc2)); - nc2.addUnwantedCapability(NET_CAPABILITY_INTERNET); - assertTrue(nc1.equalsNetCapabilities(nc2)); if (isAtLeastS()) { - // Remove a required capability doesn't affect unwanted capabilities. - // This is a behaviour change from S. - nc1.removeCapability(NET_CAPABILITY_INTERNET); - assertTrue(nc1.equalsNetCapabilities(nc2)); - - nc1.removeUnwantedCapability(NET_CAPABILITY_INTERNET); + nc1.addForbiddenCapability(NET_CAPABILITY_INTERNET); assertFalse(nc1.equalsNetCapabilities(nc2)); - nc2.removeUnwantedCapability(NET_CAPABILITY_INTERNET); + nc2.addForbiddenCapability(NET_CAPABILITY_INTERNET); assertTrue(nc1.equalsNetCapabilities(nc2)); - } else { + + // Remove a required capability doesn't affect forbidden capabilities. + // This is a behaviour change from R to S. nc1.removeCapability(NET_CAPABILITY_INTERNET); + assertTrue(nc1.equalsNetCapabilities(nc2)); + + nc1.removeForbiddenCapability(NET_CAPABILITY_INTERNET); assertFalse(nc1.equalsNetCapabilities(nc2)); - nc2.removeCapability(NET_CAPABILITY_INTERNET); + nc2.removeForbiddenCapability(NET_CAPABILITY_INTERNET); assertTrue(nc1.equalsNetCapabilities(nc2)); } } @@ -581,31 +579,25 @@ public class NetworkCapabilitiesTest { NetworkCapabilities nc1 = new NetworkCapabilities(); NetworkCapabilities nc2 = new NetworkCapabilities(); - nc1.addUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL); + if (isAtLeastS()) { + nc1.addForbiddenCapability(NET_CAPABILITY_CAPTIVE_PORTAL); + } nc1.addCapability(NET_CAPABILITY_NOT_ROAMING); assertNotEquals(nc1, nc2); nc2.combineCapabilities(nc1); assertEquals(nc1, nc2); assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); - - // This will effectively move NOT_ROAMING capability from required to unwanted for nc1. - nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING); + if (isAtLeastS()) { + assertTrue(nc2.hasForbiddenCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); + } if (isAtLeastS()) { - // From S, it is not allowed to have the same capability in both wanted and - // unwanted list. + // This will effectively move NOT_ROAMING capability from required to forbidden for nc1. + nc1.addForbiddenCapability(NET_CAPABILITY_NOT_ROAMING); + // It is not allowed to have the same capability in both wanted and forbidden list. assertThrows(IllegalArgumentException.class, () -> nc2.combineCapabilities(nc1)); - // Remove unwanted capability to continue other tests. - nc1.removeUnwantedCapability(NET_CAPABILITY_NOT_ROAMING); - } else { - nc2.combineCapabilities(nc1); - // We will get this capability in both requested and unwanted lists thus this request - // will never be satisfied. - assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING)); - // For R or below, remove unwanted capability via removeCapability. - nc1.removeCapability(NET_CAPABILITY_NOT_ROAMING); + // Remove forbidden capability to continue other tests. + nc1.removeForbiddenCapability(NET_CAPABILITY_NOT_ROAMING); } nc1.setSSID(TEST_SSID); @@ -683,14 +675,11 @@ public class NetworkCapabilitiesTest { public void testSetCapabilities() { final int[] REQUIRED_CAPABILITIES = new int[] { NET_CAPABILITY_INTERNET, NET_CAPABILITY_NOT_VPN }; - final int[] UNWANTED_CAPABILITIES = new int[] { - NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_METERED - }; NetworkCapabilities nc1 = new NetworkCapabilities(); NetworkCapabilities nc2 = new NetworkCapabilities(); - nc1.setCapabilities(REQUIRED_CAPABILITIES, UNWANTED_CAPABILITIES); + nc1.setCapabilities(REQUIRED_CAPABILITIES); assertArrayEquals(REQUIRED_CAPABILITIES, nc1.getCapabilities()); // Verify that setting and adding capabilities leads to the same object state. @@ -698,10 +687,25 @@ public class NetworkCapabilitiesTest { for (int cap : REQUIRED_CAPABILITIES) { nc2.addCapability(cap); } - for (int cap : UNWANTED_CAPABILITIES) { - nc2.addUnwantedCapability(cap); - } assertEquals(nc1, nc2); + + if (isAtLeastS()) { + final int[] forbiddenCapabilities = new int[]{ + NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_RESTRICTED }; + + nc1.setCapabilities(REQUIRED_CAPABILITIES, forbiddenCapabilities); + assertArrayEquals(REQUIRED_CAPABILITIES, nc1.getCapabilities()); + assertArrayEquals(forbiddenCapabilities, nc1.getForbiddenCapabilities()); + + nc2.clearAll(); + for (int cap : REQUIRED_CAPABILITIES) { + nc2.addCapability(cap); + } + for (int cap : forbiddenCapabilities) { + nc2.addForbiddenCapability(cap); + } + assertEquals(nc1, nc2); + } } @Test @@ -769,23 +773,32 @@ public class NetworkCapabilitiesTest { NetworkCapabilities nc1 = new NetworkCapabilities(); NetworkCapabilities nc2 = new NetworkCapabilities(); - nc1.addUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL); + if (isAtLeastS()) { + nc1.addForbiddenCapability(NET_CAPABILITY_CAPTIVE_PORTAL); + } nc1.addCapability(NET_CAPABILITY_NOT_ROAMING); assertNotEquals(nc1, nc2); nc2.set(nc1); assertEquals(nc1, nc2); assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); + if (isAtLeastS()) { + assertTrue(nc2.hasForbiddenCapability(NET_CAPABILITY_CAPTIVE_PORTAL)); + } - // This will effectively move NOT_ROAMING capability from required to unwanted for nc1. - nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING); + if (isAtLeastS()) { + // This will effectively move NOT_ROAMING capability from required to forbidden for nc1. + nc1.addForbiddenCapability(NET_CAPABILITY_NOT_ROAMING); + } nc1.setSSID(TEST_SSID); nc2.set(nc1); assertEquals(nc1, nc2); - // Contrary to combineCapabilities, set() will have removed the NOT_ROAMING capability - // from nc2. - assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING)); + if (isAtLeastS()) { + // Contrary to combineCapabilities, set() will have removed the NOT_ROAMING capability + // from nc2. + assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(nc2.hasForbiddenCapability(NET_CAPABILITY_NOT_ROAMING)); + } + if (isAtLeastR()) { assertTrue(TEST_SSID.equals(nc2.getSsid())); } diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/packages/Connectivity/tests/common/java/android/net/NetworkProviderTest.kt index 340e6f963137..340e6f963137 100644 --- a/tests/net/common/java/android/net/NetworkProviderTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/NetworkProviderTest.kt diff --git a/tests/net/common/java/android/net/NetworkSpecifierTest.kt b/packages/Connectivity/tests/common/java/android/net/NetworkSpecifierTest.kt index f3409f53596f..f3409f53596f 100644 --- a/tests/net/common/java/android/net/NetworkSpecifierTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/NetworkSpecifierTest.kt diff --git a/tests/net/common/java/android/net/NetworkStackTest.java b/packages/Connectivity/tests/common/java/android/net/NetworkStackTest.java index f8f9c72374ad..f8f9c72374ad 100644 --- a/tests/net/common/java/android/net/NetworkStackTest.java +++ b/packages/Connectivity/tests/common/java/android/net/NetworkStackTest.java diff --git a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt b/packages/Connectivity/tests/common/java/android/net/NetworkStateSnapshotTest.kt index 0ca4d9551f39..0ca4d9551f39 100644 --- a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/NetworkStateSnapshotTest.kt diff --git a/tests/net/common/java/android/net/NetworkTest.java b/packages/Connectivity/tests/common/java/android/net/NetworkTest.java index 11d44b86bc50..11d44b86bc50 100644 --- a/tests/net/common/java/android/net/NetworkTest.java +++ b/packages/Connectivity/tests/common/java/android/net/NetworkTest.java diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/packages/Connectivity/tests/common/java/android/net/OemNetworkPreferencesTest.java index fd29a9539de8..fd29a9539de8 100644 --- a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java +++ b/packages/Connectivity/tests/common/java/android/net/OemNetworkPreferencesTest.java diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/packages/Connectivity/tests/common/java/android/net/RouteInfoTest.java index 71689f919726..71689f919726 100644 --- a/tests/net/common/java/android/net/RouteInfoTest.java +++ b/packages/Connectivity/tests/common/java/android/net/RouteInfoTest.java diff --git a/tests/net/common/java/android/net/StaticIpConfigurationTest.java b/packages/Connectivity/tests/common/java/android/net/StaticIpConfigurationTest.java index b5f23bf19a3c..b5f23bf19a3c 100644 --- a/tests/net/common/java/android/net/StaticIpConfigurationTest.java +++ b/packages/Connectivity/tests/common/java/android/net/StaticIpConfigurationTest.java diff --git a/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt b/packages/Connectivity/tests/common/java/android/net/TcpKeepalivePacketDataTest.kt index 7a18bb08faa8..7a18bb08faa8 100644 --- a/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/TcpKeepalivePacketDataTest.kt diff --git a/tests/net/common/java/android/net/UidRangeTest.java b/packages/Connectivity/tests/common/java/android/net/UidRangeTest.java index 1b1c95431d6f..1b1c95431d6f 100644 --- a/tests/net/common/java/android/net/UidRangeTest.java +++ b/packages/Connectivity/tests/common/java/android/net/UidRangeTest.java diff --git a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt b/packages/Connectivity/tests/common/java/android/net/UnderlyingNetworkInfoTest.kt index 87cfb345e5e0..f23ba26d0039 100644 --- a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/UnderlyingNetworkInfoTest.kt @@ -36,15 +36,15 @@ class UnderlyingNetworkInfoTest { @Test fun testParcelUnparcel() { val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST) - assertEquals(TEST_OWNER_UID, testInfo.ownerUid) - assertEquals(TEST_IFACE, testInfo.iface) - assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces) + assertEquals(TEST_OWNER_UID, testInfo.getOwnerUid()) + assertEquals(TEST_IFACE, testInfo.getInterface()) + assertEquals(TEST_IFACE_LIST, testInfo.getUnderlyingInterfaces()) assertParcelSane(testInfo, 3) val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf()) - assertEquals(0, emptyInfo.ownerUid) - assertEquals(String(), emptyInfo.iface) - assertEquals(listOf(), emptyInfo.underlyingIfaces) + assertEquals(0, emptyInfo.getOwnerUid()) + assertEquals(String(), emptyInfo.getInterface()) + assertEquals(listOf(), emptyInfo.getUnderlyingInterfaces()) assertParcelSane(emptyInfo, 3) } }
\ No newline at end of file diff --git a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java b/packages/Connectivity/tests/common/java/android/net/apf/ApfCapabilitiesTest.java index d50406fd3a1c..d50406fd3a1c 100644 --- a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java +++ b/packages/Connectivity/tests/common/java/android/net/apf/ApfCapabilitiesTest.java diff --git a/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/ApfProgramEventTest.kt index 0b7b74097cc6..0b7b74097cc6 100644 --- a/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/ApfProgramEventTest.kt diff --git a/tests/net/common/java/android/net/metrics/ApfStatsTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/ApfStatsTest.kt index 46a8c8e5b509..46a8c8e5b509 100644 --- a/tests/net/common/java/android/net/metrics/ApfStatsTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/ApfStatsTest.kt diff --git a/tests/net/common/java/android/net/metrics/DhcpClientEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/DhcpClientEventTest.kt index 8d7a9c405024..8d7a9c405024 100644 --- a/tests/net/common/java/android/net/metrics/DhcpClientEventTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/DhcpClientEventTest.kt diff --git a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/DhcpErrorEventTest.kt index 236f72eafbdc..236f72eafbdc 100644 --- a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/DhcpErrorEventTest.kt diff --git a/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java b/packages/Connectivity/tests/common/java/android/net/metrics/IpConnectivityLogTest.java index d4780d3a5d7b..d4780d3a5d7b 100644 --- a/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java +++ b/packages/Connectivity/tests/common/java/android/net/metrics/IpConnectivityLogTest.java diff --git a/tests/net/common/java/android/net/metrics/IpManagerEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/IpManagerEventTest.kt index 64be50837fc9..64be50837fc9 100644 --- a/tests/net/common/java/android/net/metrics/IpManagerEventTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/IpManagerEventTest.kt diff --git a/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/IpReachabilityEventTest.kt index 55b5e492dd47..55b5e492dd47 100644 --- a/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/IpReachabilityEventTest.kt diff --git a/tests/net/common/java/android/net/metrics/NetworkEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/NetworkEventTest.kt index 41430b03a1eb..41430b03a1eb 100644 --- a/tests/net/common/java/android/net/metrics/NetworkEventTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/NetworkEventTest.kt diff --git a/tests/net/common/java/android/net/metrics/RaEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/RaEventTest.kt index d9b720332fbe..d9b720332fbe 100644 --- a/tests/net/common/java/android/net/metrics/RaEventTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/RaEventTest.kt diff --git a/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/ValidationProbeEventTest.kt index 51c0d41bf4d5..51c0d41bf4d5 100644 --- a/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/metrics/ValidationProbeEventTest.kt diff --git a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt b/packages/Connectivity/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt index 7b22e45db90a..7b22e45db90a 100644 --- a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt diff --git a/tests/net/common/java/android/net/util/SocketUtilsTest.kt b/packages/Connectivity/tests/common/java/android/net/util/SocketUtilsTest.kt index aaf97f36889b..aaf97f36889b 100644 --- a/tests/net/common/java/android/net/util/SocketUtilsTest.kt +++ b/packages/Connectivity/tests/common/java/android/net/util/SocketUtilsTest.kt diff --git a/tests/net/deflake/Android.bp b/packages/Connectivity/tests/deflake/Android.bp index 58ece37ef647..58ece37ef647 100644 --- a/tests/net/deflake/Android.bp +++ b/packages/Connectivity/tests/deflake/Android.bp diff --git a/tests/net/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt b/packages/Connectivity/tests/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt index 62855255fec2..62855255fec2 100644 --- a/tests/net/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt +++ b/packages/Connectivity/tests/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt diff --git a/tests/net/integration/Android.bp b/packages/Connectivity/tests/integration/Android.bp index 56f9df78c83e..56f9df78c83e 100644 --- a/tests/net/integration/Android.bp +++ b/packages/Connectivity/tests/integration/Android.bp diff --git a/tests/net/integration/AndroidManifest.xml b/packages/Connectivity/tests/integration/AndroidManifest.xml index 2e1368935759..2e1368935759 100644 --- a/tests/net/integration/AndroidManifest.xml +++ b/packages/Connectivity/tests/integration/AndroidManifest.xml diff --git a/tests/net/integration/res/values/config.xml b/packages/Connectivity/tests/integration/res/values/config.xml index 2c8046ffd781..2c8046ffd781 100644 --- a/tests/net/integration/res/values/config.xml +++ b/packages/Connectivity/tests/integration/res/values/config.xml diff --git a/tests/net/integration/src/android/net/TestNetworkStackClient.kt b/packages/Connectivity/tests/integration/src/android/net/TestNetworkStackClient.kt index 01eb514a1c81..01eb514a1c81 100644 --- a/tests/net/integration/src/android/net/TestNetworkStackClient.kt +++ b/packages/Connectivity/tests/integration/src/android/net/TestNetworkStackClient.kt diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index b6e42743e2a3..b6e42743e2a3 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl index 9a2bcfea7641..9a2bcfea7641 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl +++ b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.kt index e2063138fef1..e2063138fef1 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt +++ b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.kt diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl index efc58add9cf5..efc58add9cf5 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl +++ b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt index e807952cec11..e807952cec11 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt +++ b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt index a44ad1e05259..eff66584d6c1 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt +++ b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt @@ -61,7 +61,6 @@ class TestNetworkStackService : Service() { private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) : NetworkMonitor.Dependencies() { override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork - override fun sendNetworkConditionsBroadcast(context: Context, broadcast: Intent) = Unit } private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector( @@ -98,4 +97,4 @@ class TestNetworkStackService : Service() { cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker())) } } -}
\ No newline at end of file +} diff --git a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/packages/Connectivity/tests/integration/util/com/android/server/ConnectivityServiceTestUtils.kt index 165fd3728281..165fd3728281 100644 --- a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt +++ b/packages/Connectivity/tests/integration/util/com/android/server/ConnectivityServiceTestUtils.kt diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/packages/Connectivity/tests/integration/util/com/android/server/NetworkAgentWrapper.java index e2d43cbb8efd..e80955014fe7 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/packages/Connectivity/tests/integration/util/com/android/server/NetworkAgentWrapper.java @@ -370,4 +370,8 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { } } } + + public boolean isBypassableVpn() { + return mNetworkAgentConfig.isBypassableVpn(); + } } diff --git a/tests/net/integration/util/com/android/server/TestNetIdManager.kt b/packages/Connectivity/tests/integration/util/com/android/server/TestNetIdManager.kt index 938a694e8ba9..938a694e8ba9 100644 --- a/tests/net/integration/util/com/android/server/TestNetIdManager.kt +++ b/packages/Connectivity/tests/integration/util/com/android/server/TestNetIdManager.kt diff --git a/tests/net/smoketest/Android.bp b/packages/Connectivity/tests/smoketest/Android.bp index 1535f3ddcb38..1535f3ddcb38 100644 --- a/tests/net/smoketest/Android.bp +++ b/packages/Connectivity/tests/smoketest/Android.bp diff --git a/tests/net/smoketest/AndroidManifest.xml b/packages/Connectivity/tests/smoketest/AndroidManifest.xml index f1b9febb9f57..f1b9febb9f57 100644 --- a/tests/net/smoketest/AndroidManifest.xml +++ b/packages/Connectivity/tests/smoketest/AndroidManifest.xml diff --git a/tests/net/smoketest/AndroidTest.xml b/packages/Connectivity/tests/smoketest/AndroidTest.xml index ac366e4ac544..ac366e4ac544 100644 --- a/tests/net/smoketest/AndroidTest.xml +++ b/packages/Connectivity/tests/smoketest/AndroidTest.xml diff --git a/tests/net/smoketest/java/SmokeTest.java b/packages/Connectivity/tests/smoketest/java/SmokeTest.java index 7d6655fde15e..7d6655fde15e 100644 --- a/tests/net/smoketest/java/SmokeTest.java +++ b/packages/Connectivity/tests/smoketest/java/SmokeTest.java diff --git a/tests/net/Android.bp b/packages/Connectivity/tests/unit/Android.bp index e1a424f214a5..e1a424f214a5 100644 --- a/tests/net/Android.bp +++ b/packages/Connectivity/tests/unit/Android.bp diff --git a/tests/net/AndroidManifest.xml b/packages/Connectivity/tests/unit/AndroidManifest.xml index d08b2f8d40dd..d08b2f8d40dd 100644 --- a/tests/net/AndroidManifest.xml +++ b/packages/Connectivity/tests/unit/AndroidManifest.xml diff --git a/tests/net/AndroidTest.xml b/packages/Connectivity/tests/unit/AndroidTest.xml index 939ae493b280..939ae493b280 100644 --- a/tests/net/AndroidTest.xml +++ b/packages/Connectivity/tests/unit/AndroidTest.xml diff --git a/tests/net/jarjar-rules.txt b/packages/Connectivity/tests/unit/jarjar-rules.txt index ca8867206dda..ca8867206dda 100644 --- a/tests/net/jarjar-rules.txt +++ b/packages/Connectivity/tests/unit/jarjar-rules.txt diff --git a/tests/net/java/android/app/usage/NetworkStatsManagerTest.java b/packages/Connectivity/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java index 899295a019d2..899295a019d2 100644 --- a/tests/net/java/android/app/usage/NetworkStatsManagerTest.java +++ b/packages/Connectivity/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java index 06e9405a6a79..06e9405a6a79 100644 --- a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/ConnectivityManagerTest.java index 19f884346e6f..591e0cc3504e 100644 --- a/tests/net/java/android/net/ConnectivityManagerTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/ConnectivityManagerTest.java @@ -379,7 +379,7 @@ public class ConnectivityManagerTest { eq(testPkgName), eq(testAttributionTag)); reset(mService); - manager.registerDefaultNetworkCallbackAsUid(42, callback, handler); + manager.registerDefaultNetworkCallbackForUid(42, callback, handler); verify(mService).requestNetwork(eq(42), eq(null), eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java index 1abd39a32bdf..1abd39a32bdf 100644 --- a/tests/net/java/android/net/Ikev2VpnProfileTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/packages/Connectivity/tests/unit/java/android/net/IpMemoryStoreTest.java index 0b13800bc5c9..0b13800bc5c9 100644 --- a/tests/net/java/android/net/IpMemoryStoreTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/IpMemoryStoreTest.java diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/packages/Connectivity/tests/unit/java/android/net/IpSecAlgorithmTest.java index 3a8d6004f66f..3a8d6004f66f 100644 --- a/tests/net/java/android/net/IpSecAlgorithmTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/IpSecAlgorithmTest.java diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/packages/Connectivity/tests/unit/java/android/net/IpSecConfigTest.java index 25e225ef303a..25e225ef303a 100644 --- a/tests/net/java/android/net/IpSecConfigTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/IpSecConfigTest.java diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/IpSecManagerTest.java index 730e2d56bd78..730e2d56bd78 100644 --- a/tests/net/java/android/net/IpSecManagerTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/IpSecManagerTest.java diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/packages/Connectivity/tests/unit/java/android/net/IpSecTransformTest.java index 424f23dbbaf6..424f23dbbaf6 100644 --- a/tests/net/java/android/net/IpSecTransformTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/IpSecTransformTest.java diff --git a/tests/net/java/android/net/KeepalivePacketDataUtilTest.java b/packages/Connectivity/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java index fc739fbfac61..fc739fbfac61 100644 --- a/tests/net/java/android/net/KeepalivePacketDataUtilTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java diff --git a/tests/net/java/android/net/MacAddressTest.java b/packages/Connectivity/tests/unit/java/android/net/MacAddressTest.java index 6de31f6b4be1..6de31f6b4be1 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/MacAddressTest.java diff --git a/tests/net/java/android/net/NetworkIdentityTest.kt b/packages/Connectivity/tests/unit/java/android/net/NetworkIdentityTest.kt index eb2b85c14578..eb2b85c14578 100644 --- a/tests/net/java/android/net/NetworkIdentityTest.kt +++ b/packages/Connectivity/tests/unit/java/android/net/NetworkIdentityTest.kt diff --git a/tests/net/java/android/net/NetworkStatsHistoryTest.java b/packages/Connectivity/tests/unit/java/android/net/NetworkStatsHistoryTest.java index 13558cd51c28..13558cd51c28 100644 --- a/tests/net/java/android/net/NetworkStatsHistoryTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/NetworkStatsHistoryTest.java diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/packages/Connectivity/tests/unit/java/android/net/NetworkStatsTest.java index 735fa7cf3751..23d5a7e5d5f8 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/NetworkStatsTest.java @@ -50,6 +50,7 @@ import com.google.android.collect.Sets; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Arrays; import java.util.HashSet; @RunWith(AndroidJUnit4.class) @@ -616,7 +617,7 @@ public class NetworkStatsTest { .insertEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); - delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); + delta.migrateTun(tunUid, tunIface, Arrays.asList(underlyingIface)); assertEquals(20, delta.size()); // tunIface and TEST_IFACE entries are not changed. @@ -697,7 +698,7 @@ public class NetworkStatsTest { .insertEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L); - delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); + delta.migrateTun(tunUid, tunIface, Arrays.asList(underlyingIface)); assertEquals(9, delta.size()); // tunIface entries should not be changed. diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/packages/Connectivity/tests/unit/java/android/net/NetworkTemplateTest.kt index 64b774cc4340..ab6b2f409867 100644 --- a/tests/net/java/android/net/NetworkTemplateTest.kt +++ b/packages/Connectivity/tests/unit/java/android/net/NetworkTemplateTest.kt @@ -31,11 +31,16 @@ import android.net.NetworkTemplate.MATCH_MOBILE import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD import android.net.NetworkTemplate.MATCH_WIFI import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD +import android.net.NetworkTemplate.WIFI_NETWORKID_ALL import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA import android.net.NetworkTemplate.NETWORK_TYPE_ALL import android.net.NetworkTemplate.OEM_MANAGED_ALL import android.net.NetworkTemplate.OEM_MANAGED_NO import android.net.NetworkTemplate.OEM_MANAGED_YES +import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT +import android.net.NetworkTemplate.buildTemplateWifi +import android.net.NetworkTemplate.buildTemplateWifiWildcard +import android.net.NetworkTemplate.buildTemplateCarrier import android.net.NetworkTemplate.buildTemplateMobileWithRatType import android.telephony.TelephonyManager import com.android.testutils.assertParcelSane @@ -53,6 +58,7 @@ import kotlin.test.assertTrue private const val TEST_IMSI1 = "imsi1" private const val TEST_IMSI2 = "imsi2" private const val TEST_SSID1 = "ssid1" +private const val TEST_SSID2 = "ssid2" @RunWith(JUnit4::class) class NetworkTemplateTest { @@ -60,8 +66,8 @@ class NetworkTemplateTest { private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot = buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId) - private fun buildWifiNetworkState(ssid: String): NetworkStateSnapshot = - buildNetworkState(TYPE_WIFI, ssid = ssid) + private fun buildWifiNetworkState(subscriberId: String?, ssid: String?): NetworkStateSnapshot = + buildNetworkState(TYPE_WIFI, subscriberId = subscriberId, ssid = ssid) private fun buildNetworkState( type: Int, @@ -94,6 +100,95 @@ class NetworkTemplateTest { } @Test + fun testWifiWildcardMatches() { + val templateWifiWildcard = buildTemplateWifiWildcard() + + val identMobileImsi1 = buildNetworkIdentity(mockContext, + buildMobileNetworkState(TEST_IMSI1), + false, TelephonyManager.NETWORK_TYPE_UMTS) + val identWifiImsiNullSsid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0) + val identWifiImsi1Ssid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0) + + templateWifiWildcard.assertDoesNotMatch(identMobileImsi1) + templateWifiWildcard.assertMatches(identWifiImsiNullSsid1) + templateWifiWildcard.assertMatches(identWifiImsi1Ssid1) + } + + @Test + fun testWifiMatches() { + val templateWifiSsid1 = buildTemplateWifi(TEST_SSID1) + val templateWifiSsid1ImsiNull = buildTemplateWifi(TEST_SSID1, null) + val templateWifiSsid1Imsi1 = buildTemplateWifi(TEST_SSID1, TEST_IMSI1) + val templateWifiSsidAllImsi1 = buildTemplateWifi(WIFI_NETWORKID_ALL, TEST_IMSI1) + + val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1), + false, TelephonyManager.NETWORK_TYPE_UMTS) + val identWifiImsiNullSsid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0) + val identWifiImsi1Ssid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0) + val identWifiImsi2Ssid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0) + val identWifiImsi1Ssid2 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID2), true, 0) + + // Verify that template with SSID only matches any subscriberId and specific SSID. + templateWifiSsid1.assertDoesNotMatch(identMobile1) + templateWifiSsid1.assertMatches(identWifiImsiNullSsid1) + templateWifiSsid1.assertMatches(identWifiImsi1Ssid1) + templateWifiSsid1.assertMatches(identWifiImsi2Ssid1) + templateWifiSsid1.assertDoesNotMatch(identWifiImsi1Ssid2) + + // Verify that template with SSID1 and null imsi matches any network with + // SSID1 and null imsi. + templateWifiSsid1ImsiNull.assertDoesNotMatch(identMobile1) + templateWifiSsid1ImsiNull.assertMatches(identWifiImsiNullSsid1) + templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid1) + templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi2Ssid1) + templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid2) + + // Verify that template with SSID1 and imsi1 matches any network with + // SSID1 and imsi1. + templateWifiSsid1Imsi1.assertDoesNotMatch(identMobile1) + templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsiNullSsid1) + templateWifiSsid1Imsi1.assertMatches(identWifiImsi1Ssid1) + templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi2Ssid1) + templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi1Ssid2) + + // Verify that template with SSID all and imsi1 matches any network with + // any SSID and imsi1. + templateWifiSsidAllImsi1.assertDoesNotMatch(identMobile1) + templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsiNullSsid1) + templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid1) + templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsi2Ssid1) + templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid2) + } + + @Test + fun testCarrierMatches() { + val templateCarrierImsi1 = buildTemplateCarrier(TEST_IMSI1) + + val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1), + false, TelephonyManager.NETWORK_TYPE_UMTS) + val identMobile2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2), + false, TelephonyManager.NETWORK_TYPE_UMTS) + val identWifiSsid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0) + val identCarrierWifiImsi1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0) + val identCarrierWifiImsi2 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0) + + templateCarrierImsi1.assertMatches(identCarrierWifiImsi1) + templateCarrierImsi1.assertDoesNotMatch(identCarrierWifiImsi2) + templateCarrierImsi1.assertDoesNotMatch(identWifiSsid1) + templateCarrierImsi1.assertMatches(identMobile1) + templateCarrierImsi1.assertDoesNotMatch(identMobile2) + } + + @Test fun testRatTypeGroupMatches() { val stateMobile = buildMobileNetworkState(TEST_IMSI1) // Build UMTS template that matches mobile identities with RAT in the same @@ -117,7 +212,7 @@ class NetworkTemplateTest { val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2), false, TelephonyManager.NETWORK_TYPE_UMTS) val identWifi = buildNetworkIdentity( - mockContext, buildWifiNetworkState(TEST_SSID1), true, 0) + mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0) // Assert that identity with the same RAT matches. templateUmts.assertMatches(identUmts) @@ -151,14 +246,16 @@ class NetworkTemplateTest { fun testParcelUnparcel() { val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE, - OEM_MANAGED_ALL) + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL, - ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL) + ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT) val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL, - ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES) - assertParcelSane(templateMobile, 9) - assertParcelSane(templateWifi, 9) - assertParcelSane(templateOem, 9) + ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES, + SUBSCRIBER_ID_MATCH_RULE_EXACT) + assertParcelSane(templateMobile, 10) + assertParcelSane(templateWifi, 10) + assertParcelSane(templateOem, 10) } // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with @@ -207,15 +304,14 @@ class NetworkTemplateTest { identSsid: String? = null ) { val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE) - // A null subscriberId needs a null matchSubscriberIds argument as well. - val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId) + val matchSubscriberIds = arrayOf(subscriberId) val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_YES) + OEM_MANAGED_YES, SUBSCRIBER_ID_MATCH_RULE_EXACT) val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL) + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) for (identityOemManagedState in oemManagedStates) { val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType, @@ -226,7 +322,7 @@ class NetworkTemplateTest { for (templateOemManagedState in oemManagedStates) { val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, - NETWORK_TYPE_ALL, templateOemManagedState) + NETWORK_TYPE_ALL, templateOemManagedState, SUBSCRIBER_ID_MATCH_RULE_EXACT) if (identityOemManagedState == templateOemManagedState) { template.assertMatches(ident) } else { diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/packages/Connectivity/tests/unit/java/android/net/NetworkUtilsTest.java index 7748288aeb05..7748288aeb05 100644 --- a/tests/net/java/android/net/NetworkUtilsTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/NetworkUtilsTest.java diff --git a/tests/net/java/android/net/QosSocketFilterTest.java b/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java index ad58960eaadd..40f8f1b8d09a 100644 --- a/tests/net/java/android/net/QosSocketFilterTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java @@ -35,7 +35,7 @@ public class QosSocketFilterTest { public void testPortExactMatch() { final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4"); final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4"); - assertTrue(QosSocketFilter.matchesLocalAddress( + assertTrue(QosSocketFilter.matchesAddress( new InetSocketAddress(addressA, 10), addressB, 10, 10)); } @@ -44,7 +44,7 @@ public class QosSocketFilterTest { public void testPortLessThanStart() { final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4"); final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4"); - assertFalse(QosSocketFilter.matchesLocalAddress( + assertFalse(QosSocketFilter.matchesAddress( new InetSocketAddress(addressA, 8), addressB, 10, 10)); } @@ -52,7 +52,7 @@ public class QosSocketFilterTest { public void testPortGreaterThanEnd() { final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4"); final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4"); - assertFalse(QosSocketFilter.matchesLocalAddress( + assertFalse(QosSocketFilter.matchesAddress( new InetSocketAddress(addressA, 18), addressB, 10, 10)); } @@ -60,7 +60,7 @@ public class QosSocketFilterTest { public void testPortBetweenStartAndEnd() { final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4"); final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4"); - assertTrue(QosSocketFilter.matchesLocalAddress( + assertTrue(QosSocketFilter.matchesAddress( new InetSocketAddress(addressA, 10), addressB, 8, 18)); } @@ -68,7 +68,7 @@ public class QosSocketFilterTest { public void testAddressesDontMatch() { final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4"); final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5"); - assertFalse(QosSocketFilter.matchesLocalAddress( + assertFalse(QosSocketFilter.matchesAddress( new InetSocketAddress(addressA, 10), addressB, 10, 10)); } } diff --git a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java b/packages/Connectivity/tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java index 6714bb1abbe6..6714bb1abbe6 100644 --- a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java diff --git a/tests/net/java/android/net/VpnManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/VpnManagerTest.java index c548e30761c9..3135062138ac 100644 --- a/tests/net/java/android/net/VpnManagerTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/VpnManagerTest.java @@ -28,11 +28,13 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Intent; import android.test.mock.MockContext; +import android.util.SparseArray; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.net.VpnProfile; +import com.android.internal.util.MessageUtils; import org.junit.Before; import org.junit.Test; @@ -119,4 +121,18 @@ public class VpnManagerTest { .setAuthPsk(PSK_BYTES) .build(); } + + @Test + public void testVpnTypesEqual() throws Exception { + SparseArray<String> vmVpnTypes = MessageUtils.findMessageNames( + new Class[] { VpnManager.class }, new String[]{ "TYPE_VPN_" }); + SparseArray<String> nativeVpnType = MessageUtils.findMessageNames( + new Class[] { NativeVpnType.class }, new String[]{ "" }); + + // TYPE_VPN_NONE = -1 is only defined in VpnManager. + assertEquals(vmVpnTypes.size() - 1, nativeVpnType.size()); + for (int i = VpnManager.TYPE_VPN_SERVICE; i < vmVpnTypes.size(); i++) { + assertEquals(vmVpnTypes.get(i), "TYPE_VPN_" + nativeVpnType.get(i)); + } + } } diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/packages/Connectivity/tests/unit/java/android/net/VpnTransportInfoTest.java index fee65f06bcad..ccaa5cf7e9f7 100644 --- a/tests/net/java/android/net/VpnTransportInfoTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/VpnTransportInfoTest.java @@ -63,6 +63,6 @@ public class VpnTransportInfoTest { assertEquals(v31, v32); assertEquals(v11.hashCode(), v13.hashCode()); assertEquals(REDACT_FOR_NETWORK_SETTINGS, v32.getApplicableRedactions()); - assertEquals(session1, v15.makeCopy(REDACT_NONE).sessionId); + assertEquals(session1, v15.makeCopy(REDACT_NONE).getSessionId()); } } diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/packages/Connectivity/tests/unit/java/android/net/ipmemorystore/ParcelableTests.java index 603c87519532..603c87519532 100644 --- a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java +++ b/packages/Connectivity/tests/unit/java/android/net/ipmemorystore/ParcelableTests.java diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/nsd/NsdManagerTest.java index b0a9b8a55322..b0a9b8a55322 100644 --- a/tests/net/java/android/net/nsd/NsdManagerTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/nsd/NsdManagerTest.java diff --git a/tests/net/java/android/net/nsd/NsdServiceInfoTest.java b/packages/Connectivity/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java index 94dfc7515c67..94dfc7515c67 100644 --- a/tests/net/java/android/net/nsd/NsdServiceInfoTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java diff --git a/tests/net/java/android/net/util/DnsUtilsTest.java b/packages/Connectivity/tests/unit/java/android/net/util/DnsUtilsTest.java index b626db8d89e4..b626db8d89e4 100644 --- a/tests/net/java/android/net/util/DnsUtilsTest.java +++ b/packages/Connectivity/tests/unit/java/android/net/util/DnsUtilsTest.java diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/packages/Connectivity/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt index b62bdbcfb5eb..b62bdbcfb5eb 100644 --- a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt +++ b/packages/Connectivity/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/packages/Connectivity/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt index 25aa6266577e..25aa6266577e 100644 --- a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt +++ b/packages/Connectivity/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt diff --git a/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/net/NetworkUtilsInternalTest.java index 3cfecd552967..3cfecd552967 100644 --- a/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/internal/net/NetworkUtilsInternalTest.java diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java index 46597d19ef1b..46597d19ef1b 100644 --- a/tests/net/java/com/android/internal/net/VpnProfileTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java diff --git a/tests/net/java/com/android/internal/util/BitUtilsTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/util/BitUtilsTest.java index d2fbdce9771a..d2fbdce9771a 100644 --- a/tests/net/java/com/android/internal/util/BitUtilsTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/internal/util/BitUtilsTest.java diff --git a/tests/net/java/com/android/internal/util/RingBufferTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/util/RingBufferTest.java index d06095a690cf..d06095a690cf 100644 --- a/tests/net/java/com/android/internal/util/RingBufferTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/internal/util/RingBufferTest.java diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 8bf98b48da36..41458f16baa4 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -19,6 +19,7 @@ package com.android.server; import static android.Manifest.permission.CHANGE_NETWORK_STATE; import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.LOCAL_MAC_ADDRESS; import static android.Manifest.permission.NETWORK_FACTORY; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.app.PendingIntent.FLAG_IMMUTABLE; @@ -44,9 +45,6 @@ import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO; import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; import static android.net.ConnectivityManager.TYPE_ETHERNET; @@ -57,6 +55,9 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP; @@ -126,6 +127,7 @@ import static com.android.testutils.MiscAsserts.assertContainsExactly; import static com.android.testutils.MiscAsserts.assertEmpty; import static com.android.testutils.MiscAsserts.assertLength; import static com.android.testutils.MiscAsserts.assertRunsInAtMost; +import static com.android.testutils.MiscAsserts.assertSameElements; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; @@ -211,6 +213,8 @@ import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MatchAllNetworkSpecifier; +import android.net.NativeNetworkConfig; +import android.net.NativeNetworkType; import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkAgentConfig; @@ -1253,6 +1257,8 @@ public class ConnectivityServiceTest { verify(mMockNetd, never()) .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any()); mAgentRegistered = true; + verify(mMockNetd).networkCreate(nativeNetworkConfigVpn(getNetwork().netId, + !mMockNetworkAgent.isBypassableVpn(), mVpnType)); updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent"); mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities()); mNetworkAgent = mMockNetworkAgent.getNetworkAgent(); @@ -1400,7 +1406,7 @@ public class ConnectivityServiceTest { final TransportInfo ti = nc.getTransportInfo(); assertTrue("VPN TransportInfo is not a VpnTransportInfo: " + ti, ti instanceof VpnTransportInfo); - assertEquals(type, ((VpnTransportInfo) ti).type); + assertEquals(type, ((VpnTransportInfo) ti).getType()); } @@ -1804,7 +1810,7 @@ public class ConnectivityServiceTest { assertNull(mCm.getActiveNetworkForUid(Process.myUid())); // Test getAllNetworks() assertEmpty(mCm.getAllNetworks()); - assertEmpty(mCm.getAllNetworkStateSnapshot()); + assertEmpty(mCm.getAllNetworkStateSnapshots()); } /** @@ -2809,8 +2815,9 @@ public class ConnectivityServiceTest { private void grantUsingBackgroundNetworksPermissionForUid( final int uid, final String packageName) throws Exception { - when(mPackageManager.getPackageInfo(eq(packageName), eq(GET_PERMISSIONS))) - .thenReturn(buildPackageInfo(true, uid)); + when(mPackageManager.getPackageInfo( + eq(packageName), eq(GET_PERMISSIONS | MATCH_ANY_USER))) + .thenReturn(buildPackageInfo(true /* hasSystemPermission */, uid)); mService.mPermissionMonitor.onPackageAdded(packageName, uid); } @@ -2860,6 +2867,16 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(callback); } + private NativeNetworkConfig nativeNetworkConfigPhysical(int netId, int permission) { + return new NativeNetworkConfig(netId, NativeNetworkType.PHYSICAL, permission, + /*secure=*/ false, VpnManager.TYPE_VPN_NONE); + } + + private NativeNetworkConfig nativeNetworkConfigVpn(int netId, boolean secure, int vpnType) { + return new NativeNetworkConfig(netId, NativeNetworkType.VIRTUAL, INetd.PERMISSION_NONE, + secure, vpnType); + } + @Test public void testNetworkAgentCallbacks() throws Exception { // Keeps track of the order of events that happen in this test. @@ -2881,8 +2898,8 @@ public class ConnectivityServiceTest { wifiNetwork.set(mWiFiNetworkAgent.getNetwork()); assertNotNull(wifiNetwork.get()); try { - verify(mMockNetd).networkCreatePhysical(wifiNetwork.get().getNetId(), - INetd.PERMISSION_NONE); + verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( + wifiNetwork.get().getNetId(), INetd.PERMISSION_NONE)); } catch (RemoteException impossible) { fail(); } @@ -2928,7 +2945,7 @@ public class ConnectivityServiceTest { callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); // Set teardown delay and make sure CS has processed it. - mWiFiNetworkAgent.getNetworkAgent().setTeardownDelayMs(300); + mWiFiNetworkAgent.getNetworkAgent().setTeardownDelayMillis(300); waitForIdle(); // Post the duringTeardown lambda to the handler so it fires while teardown is in progress. @@ -4216,7 +4233,7 @@ public class ConnectivityServiceTest { () -> mCm.registerSystemDefaultNetworkCallback(callback, handler)); callback.assertNoCallback(); assertThrows(SecurityException.class, - () -> mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler)); + () -> mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler)); callback.assertNoCallback(); mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED); @@ -4224,7 +4241,7 @@ public class ConnectivityServiceTest { callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); mCm.unregisterNetworkCallback(callback); - mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler); + mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler); callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); mCm.unregisterNetworkCallback(callback); } @@ -4242,10 +4259,9 @@ public class ConnectivityServiceTest { waitForIdle(); } - private void setPrivateDnsSettings(String mode, String specifier) { - final ContentResolver cr = mServiceContext.getContentResolver(); - Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_MODE, mode); - Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER, specifier); + private void setPrivateDnsSettings(int mode, String specifier) { + ConnectivitySettingsManager.setPrivateDnsMode(mServiceContext, mode); + ConnectivitySettingsManager.setPrivateDnsHostname(mServiceContext, specifier); mService.updatePrivateDnsSettings(); waitForIdle(); } @@ -5600,7 +5616,7 @@ public class ConnectivityServiceTest { for (int i = 0; i < SYSTEM_ONLY_MAX_REQUESTS - 1; i++) { NetworkCallback cb = new NetworkCallback(); if (i % 2 == 0) { - mCm.registerDefaultNetworkCallbackAsUid(1000000 + i, cb, handler); + mCm.registerDefaultNetworkCallbackForUid(1000000 + i, cb, handler); } else { mCm.registerNetworkCallback(networkRequest, cb); } @@ -5609,7 +5625,7 @@ public class ConnectivityServiceTest { waitForIdle(); assertThrows(TooManyRequestsException.class, () -> - mCm.registerDefaultNetworkCallbackAsUid(1001042, new NetworkCallback(), + mCm.registerDefaultNetworkCallbackForUid(1001042, new NetworkCallback(), handler)); assertThrows(TooManyRequestsException.class, () -> mCm.registerNetworkCallback(networkRequest, new NetworkCallback())); @@ -5662,7 +5678,7 @@ public class ConnectivityServiceTest { withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> { for (int i = 0; i < MAX_REQUESTS; i++) { NetworkCallback networkCallback = new NetworkCallback(); - mCm.registerDefaultNetworkCallbackAsUid(1000000 + i, networkCallback, + mCm.registerDefaultNetworkCallbackForUid(1000000 + i, networkCallback, new Handler(ConnectivityThread.getInstanceLooper())); mCm.unregisterNetworkCallback(networkCallback); } @@ -5791,20 +5807,8 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(networkCallback); } - private <T> void assertSameElementsNoDuplicates(T[] expected, T[] actual) { - // Easier to implement than a proper "assertSameElements" method that also correctly deals - // with duplicates. - final String msg = Arrays.toString(expected) + " != " + Arrays.toString(actual); - assertEquals(msg, expected.length, actual.length); - Set expectedSet = new ArraySet<>(Arrays.asList(expected)); - assertEquals("expected contains duplicates", expectedSet.size(), expected.length); - // actual cannot have duplicates because it's the same length and has the same elements. - Set actualSet = new ArraySet<>(Arrays.asList(actual)); - assertEquals(expectedSet, actualSet); - } - - private void expectNetworkStatus(Network[] networks, String defaultIface, - Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception { + private void expectNotifyNetworkStatus(List<Network> networks, String defaultIface, + Integer vpnUid, String vpnIfname, List<String> underlyingIfaces) throws Exception { ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class); ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor = ArgumentCaptor.forClass(List.class); @@ -5812,26 +5816,24 @@ public class ConnectivityServiceTest { verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(), any(List.class), eq(defaultIface), vpnInfosCaptor.capture()); - assertSameElementsNoDuplicates(networksCaptor.getValue().toArray(), networks); + assertSameElements(networksCaptor.getValue(), networks); - UnderlyingNetworkInfo[] infos = - vpnInfosCaptor.getValue().toArray(new UnderlyingNetworkInfo[0]); + List<UnderlyingNetworkInfo> infos = vpnInfosCaptor.getValue(); if (vpnUid != null) { - assertEquals("Should have exactly one VPN:", 1, infos.length); - UnderlyingNetworkInfo info = infos[0]; - assertEquals("Unexpected VPN owner:", (int) vpnUid, info.ownerUid); - assertEquals("Unexpected VPN interface:", vpnIfname, info.iface); - assertSameElementsNoDuplicates(underlyingIfaces, - info.underlyingIfaces.toArray(new String[0])); + assertEquals("Should have exactly one VPN:", 1, infos.size()); + UnderlyingNetworkInfo info = infos.get(0); + assertEquals("Unexpected VPN owner:", (int) vpnUid, info.getOwnerUid()); + assertEquals("Unexpected VPN interface:", vpnIfname, info.getInterface()); + assertSameElements(underlyingIfaces, info.getUnderlyingInterfaces()); } else { - assertEquals(0, infos.length); + assertEquals(0, infos.size()); return; } } - private void expectNetworkStatus( - Network[] networks, String defaultIface) throws Exception { - expectNetworkStatus(networks, defaultIface, null, null, new String[0]); + private void expectNotifyNetworkStatus( + List<Network> networks, String defaultIface) throws Exception { + expectNotifyNetworkStatus(networks, defaultIface, null, null, List.of()); } @Test @@ -5839,8 +5841,8 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - final Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()}; - final Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()}; + final List<Network> onlyCell = List.of(mCellNetworkAgent.getNetwork()); + final List<Network> onlyWifi = List.of(mWiFiNetworkAgent.getNetwork()); LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); @@ -5851,7 +5853,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(false); mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); - expectNetworkStatus(onlyCell, MOBILE_IFNAME); + expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME); reset(mStatsManager); // Default network switch should update ifaces. @@ -5859,37 +5861,37 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.sendLinkProperties(wifiLp); waitForIdle(); assertEquals(wifiLp, mService.getActiveLinkProperties()); - expectNetworkStatus(onlyWifi, WIFI_IFNAME); + expectNotifyNetworkStatus(onlyWifi, WIFI_IFNAME); reset(mStatsManager); // Disconnect should update ifaces. mWiFiNetworkAgent.disconnect(); waitForIdle(); - expectNetworkStatus(onlyCell, MOBILE_IFNAME); + expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME); reset(mStatsManager); // Metered change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - expectNetworkStatus(onlyCell, MOBILE_IFNAME); + expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME); reset(mStatsManager); mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - expectNetworkStatus(onlyCell, MOBILE_IFNAME); + expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME); reset(mStatsManager); // Temp metered change shouldn't update ifaces mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); waitForIdle(); - verify(mStatsManager, never()).notifyNetworkStatus(eq(Arrays.asList(onlyCell)), + verify(mStatsManager, never()).notifyNetworkStatus(eq(onlyCell), any(List.class), eq(MOBILE_IFNAME), any(List.class)); reset(mStatsManager); // Roaming change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); waitForIdle(); - expectNetworkStatus(onlyCell, MOBILE_IFNAME); + expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME); reset(mStatsManager); // Test VPNs. @@ -5899,29 +5901,29 @@ public class ConnectivityServiceTest { mMockVpn.establishForMyUid(lp); assertUidRangesUpdatedForMyUid(true); - final Network[] cellAndVpn = new Network[] { - mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()}; + final List<Network> cellAndVpn = + List.of(mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()); // A VPN with default (null) underlying networks sets the underlying network's interfaces... - expectNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, - new String[]{MOBILE_IFNAME}); + expectNotifyNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + List.of(MOBILE_IFNAME)); // ...and updates them as the default network switches. mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); mWiFiNetworkAgent.sendLinkProperties(wifiLp); final Network[] onlyNull = new Network[]{null}; - final Network[] wifiAndVpn = new Network[] { - mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()}; - final Network[] cellAndWifi = new Network[] { - mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()}; - final Network[] cellNullAndWifi = new Network[] { - mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()}; + final List<Network> wifiAndVpn = + List.of(mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()); + final List<Network> cellAndWifi = + List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()); + final Network[] cellNullAndWifi = + new Network[]{mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()}; waitForIdle(); assertEquals(wifiLp, mService.getActiveLinkProperties()); - expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME, - new String[]{WIFI_IFNAME}); + expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME, + List.of(WIFI_IFNAME)); reset(mStatsManager); // A VPN that sets its underlying networks passes the underlying interfaces, and influences @@ -5930,23 +5932,23 @@ public class ConnectivityServiceTest { // MOBILE_IFNAME even though the default network is wifi. // TODO: fix this to pass in the actual default network interface. Whether or not the VPN // applies to the system server UID should not have any bearing on network stats. - mMockVpn.setUnderlyingNetworks(onlyCell); + mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0])); waitForIdle(); - expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, - new String[]{MOBILE_IFNAME}); + expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + List.of(MOBILE_IFNAME)); reset(mStatsManager); - mMockVpn.setUnderlyingNetworks(cellAndWifi); + mMockVpn.setUnderlyingNetworks(cellAndWifi.toArray(new Network[0])); waitForIdle(); - expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, - new String[]{MOBILE_IFNAME, WIFI_IFNAME}); + expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + List.of(MOBILE_IFNAME, WIFI_IFNAME)); reset(mStatsManager); // Null underlying networks are ignored. mMockVpn.setUnderlyingNetworks(cellNullAndWifi); waitForIdle(); - expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, - new String[]{MOBILE_IFNAME, WIFI_IFNAME}); + expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + List.of(MOBILE_IFNAME, WIFI_IFNAME)); reset(mStatsManager); // If an underlying network disconnects, that interface should no longer be underlying. @@ -5959,15 +5961,15 @@ public class ConnectivityServiceTest { mCellNetworkAgent.disconnect(); waitForIdle(); assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork())); - expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, - new String[]{MOBILE_IFNAME, WIFI_IFNAME}); + expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + List.of(MOBILE_IFNAME, WIFI_IFNAME)); // Confirm that we never tell NetworkStatsService that cell is no longer the underlying // network for the VPN... verify(mStatsManager, never()).notifyNetworkStatus(any(List.class), any(List.class), any() /* anyString() doesn't match null */, - argThat(infos -> infos.get(0).underlyingIfaces.size() == 1 - && WIFI_IFNAME.equals(infos.get(0).underlyingIfaces.get(0)))); + argThat(infos -> infos.get(0).getUnderlyingInterfaces().size() == 1 + && WIFI_IFNAME.equals(infos.get(0).getUnderlyingInterfaces().get(0)))); verifyNoMoreInteractions(mStatsManager); reset(mStatsManager); @@ -5980,8 +5982,8 @@ public class ConnectivityServiceTest { waitForIdle(); verify(mStatsManager).notifyNetworkStatus(any(List.class), any(List.class), any() /* anyString() doesn't match null */, - argThat(vpnInfos -> vpnInfos.get(0).underlyingIfaces.size() == 1 - && WIFI_IFNAME.equals(vpnInfos.get(0).underlyingIfaces.get(0)))); + argThat(vpnInfos -> vpnInfos.get(0).getUnderlyingInterfaces().size() == 1 + && WIFI_IFNAME.equals(vpnInfos.get(0).getUnderlyingInterfaces().get(0)))); mEthernetNetworkAgent.disconnect(); waitForIdle(); reset(mStatsManager); @@ -5994,26 +5996,26 @@ public class ConnectivityServiceTest { // Also, for the same reason as above, the active interface passed in is null. mMockVpn.setUnderlyingNetworks(new Network[0]); waitForIdle(); - expectNetworkStatus(wifiAndVpn, null); + expectNotifyNetworkStatus(wifiAndVpn, null); reset(mStatsManager); // Specifying only a null underlying network is the same as no networks. mMockVpn.setUnderlyingNetworks(onlyNull); waitForIdle(); - expectNetworkStatus(wifiAndVpn, null); + expectNotifyNetworkStatus(wifiAndVpn, null); reset(mStatsManager); // Specifying networks that are all disconnected is the same as specifying no networks. - mMockVpn.setUnderlyingNetworks(onlyCell); + mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0])); waitForIdle(); - expectNetworkStatus(wifiAndVpn, null); + expectNotifyNetworkStatus(wifiAndVpn, null); reset(mStatsManager); // Passing in null again means follow the default network again. mMockVpn.setUnderlyingNetworks(null); waitForIdle(); - expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME, - new String[]{WIFI_IFNAME}); + expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME, + List.of(WIFI_IFNAME)); reset(mStatsManager); } @@ -7747,7 +7749,7 @@ public class ConnectivityServiceTest { registerDefaultNetworkCallbackAsUid(vpnUidDefaultCallback, VPN_UID); final TestNetworkCallback vpnDefaultCallbackAsUid = new TestNetworkCallback(); - mCm.registerDefaultNetworkCallbackAsUid(VPN_UID, vpnDefaultCallbackAsUid, + mCm.registerDefaultNetworkCallbackForUid(VPN_UID, vpnDefaultCallbackAsUid, new Handler(ConnectivityThread.getInstanceLooper())); final int uid = Process.myUid(); @@ -8327,7 +8329,8 @@ public class ConnectivityServiceTest { final int cellNetId = mCellNetworkAgent.getNetwork().netId; waitForIdle(); - verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt()); + verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(cellNetId, + INetd.PERMISSION_NONE)); assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute); verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId)); verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME); @@ -9392,9 +9395,9 @@ public class ConnectivityServiceTest { @Override public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) { return new TestTransportInfo( - (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0, - (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0, - (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0 + locationRedacted | (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0, + localMacAddressRedacted | (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0, + settingsRedacted | (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0 ); } @@ -9417,8 +9420,26 @@ public class ConnectivityServiceTest { public int hashCode() { return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted); } + + @Override + public String toString() { + return String.format( + "TestTransportInfo{locationRedacted=%s macRedacted=%s settingsRedacted=%s}", + locationRedacted, localMacAddressRedacted, settingsRedacted); + } } + private TestTransportInfo getTestTransportInfo(NetworkCapabilities nc) { + return (TestTransportInfo) nc.getTransportInfo(); + } + + private TestTransportInfo getTestTransportInfo(TestNetworkAgentWrapper n) { + final NetworkCapabilities nc = mCm.getNetworkCapabilities(n.getNetwork()); + assertNotNull(nc); + return getTestTransportInfo(nc); + } + + private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps( @NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid, @NonNull TransportInfo actualTransportInfo, int expectedOwnerUid, @@ -9447,7 +9468,6 @@ public class ConnectivityServiceTest { wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent, nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid()) && Objects.equals(expectedTransportInfo, nc.getTransportInfo())); - } @Test @@ -9468,6 +9488,40 @@ public class ConnectivityServiceTest { wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo); } + @Test + public void testTransportInfoRedactionInSynchronousCalls() throws Exception { + final NetworkCapabilities ncTemplate = new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI) + .setTransportInfo(new TestTransportInfo()); + + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), + ncTemplate); + mWiFiNetworkAgent.connect(true /* validated; waits for callback */); + + // NETWORK_SETTINGS redaction is controlled by the NETWORK_SETTINGS permission + assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted); + withPermission(NETWORK_SETTINGS, () -> { + assertFalse(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted); + }); + assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted); + + // LOCAL_MAC_ADDRESS redaction is controlled by the LOCAL_MAC_ADDRESS permission + assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted); + withPermission(LOCAL_MAC_ADDRESS, () -> { + assertFalse(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted); + }); + assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted); + + // Synchronous getNetworkCapabilities calls never return unredacted location-sensitive + // information. + assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted); + setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION); + assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted); + denyAllLocationPrivilegedPermissions(); + assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted); + } + private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) throws Exception { final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE); @@ -9825,12 +9879,27 @@ public class ConnectivityServiceTest { // Connect the cell agent verify that it notifies TestNetworkCallback that it is available final TestNetworkCallback callback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(callback); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + + final NetworkCapabilities ncTemplate = new NetworkCapabilities() + .addTransportType(TRANSPORT_CELLULAR) + .setTransportInfo(new TestTransportInfo()); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), + ncTemplate); mCellNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); callback.assertNoCallback(); } + private boolean areConnDiagCapsRedacted(NetworkCapabilities nc) { + TestTransportInfo ti = (TestTransportInfo) nc.getTransportInfo(); + return nc.getUids() == null + && nc.getAdministratorUids().length == 0 + && nc.getOwnerUid() == Process.INVALID_UID + && getTestTransportInfo(nc).locationRedacted + && getTestTransportInfo(nc).localMacAddressRedacted + && getTestTransportInfo(nc).settingsRedacted; + } + @Test public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable() throws Exception { @@ -9841,12 +9910,7 @@ public class ConnectivityServiceTest { // Verify onConnectivityReport fired verify(mConnectivityDiagnosticsCallback).onConnectivityReportAvailable( - argThat(report -> { - final NetworkCapabilities nc = report.getNetworkCapabilities(); - return nc.getUids() == null - && nc.getAdministratorUids().length == 0 - && nc.getOwnerUid() == Process.INVALID_UID; - })); + argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities()))); } @Test @@ -9862,12 +9926,7 @@ public class ConnectivityServiceTest { // Verify onDataStallSuspected fired verify(mConnectivityDiagnosticsCallback).onDataStallSuspected( - argThat(report -> { - final NetworkCapabilities nc = report.getNetworkCapabilities(); - return nc.getUids() == null - && nc.getAdministratorUids().length == 0 - && nc.getOwnerUid() == Process.INVALID_UID; - })); + argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities()))); } @Test @@ -10323,7 +10382,7 @@ public class ConnectivityServiceTest { assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_VALIDATED)); assertTrue(mRequests.get(1).isRequest()); assertTrue(mRequests.get(1).hasCapability(NET_CAPABILITY_OEM_PAID)); - assertTrue(mRequests.get(2).isRequest()); + assertEquals(NetworkRequest.Type.TRACK_DEFAULT, mRequests.get(2).type); assertTrue(mService.getDefaultRequest().networkCapabilities.equalsNetCapabilities( mRequests.get(2).networkCapabilities)); } @@ -10835,7 +10894,7 @@ public class ConnectivityServiceTest { final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); withPermission(NETWORK_SETTINGS, () -> - mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, + mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback, new Handler(ConnectivityThread.getInstanceLooper()))); // Setup the test process to use networkPref for their default network. @@ -10883,7 +10942,7 @@ public class ConnectivityServiceTest { final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); withPermission(NETWORK_SETTINGS, () -> - mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, + mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback, new Handler(ConnectivityThread.getInstanceLooper()))); // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. @@ -10925,7 +10984,7 @@ public class ConnectivityServiceTest { final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); withPermission(NETWORK_SETTINGS, () -> - mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, + mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback, new Handler(ConnectivityThread.getInstanceLooper()))); // Setup a process different than the test process to use the default network. This means @@ -11742,7 +11801,7 @@ public class ConnectivityServiceTest { } @Test - public void testGetAllNetworkStateSnapshot() throws Exception { + public void testGetAllNetworkStateSnapshots() throws Exception { verifyNoNetwork(); // Setup test cellular network with specified LinkProperties and NetworkCapabilities, @@ -11766,7 +11825,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp, cellNcTemplate); mCellNetworkAgent.connect(true); cellCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); - List<NetworkStateSnapshot> snapshots = mCm.getAllNetworkStateSnapshot(); + List<NetworkStateSnapshot> snapshots = mCm.getAllNetworkStateSnapshots(); assertLength(1, snapshots); // Compose the expected cellular snapshot for verification. @@ -11788,7 +11847,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.getNetwork(), wifiNc, new LinkProperties(), null, ConnectivityManager.TYPE_WIFI); - snapshots = mCm.getAllNetworkStateSnapshot(); + snapshots = mCm.getAllNetworkStateSnapshots(); assertLength(2, snapshots); assertContainsAll(snapshots, cellSnapshot, wifiSnapshot); @@ -11797,20 +11856,20 @@ public class ConnectivityServiceTest { // temporary shortage of connectivity of a connected network. mCellNetworkAgent.suspend(); waitForIdle(); - snapshots = mCm.getAllNetworkStateSnapshot(); + snapshots = mCm.getAllNetworkStateSnapshots(); assertLength(1, snapshots); assertEquals(wifiSnapshot, snapshots.get(0)); // Disconnect wifi, verify the snapshots contain nothing. mWiFiNetworkAgent.disconnect(); waitForIdle(); - snapshots = mCm.getAllNetworkStateSnapshot(); + snapshots = mCm.getAllNetworkStateSnapshots(); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertLength(0, snapshots); mCellNetworkAgent.resume(); waitForIdle(); - snapshots = mCm.getAllNetworkStateSnapshot(); + snapshots = mCm.getAllNetworkStateSnapshots(); assertLength(1, snapshots); assertEquals(cellSnapshot, snapshots.get(0)); @@ -11982,8 +12041,9 @@ public class ConnectivityServiceTest { mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId, - INetd.PERMISSION_NONE); + inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( + mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + final TestOnCompleteListener listener = new TestOnCompleteListener(); mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE, @@ -12010,8 +12070,8 @@ public class ConnectivityServiceTest { mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent); mSystemDefaultNetworkCallback.assertNoCallback(); mDefaultNetworkCallback.assertNoCallback(); - inOrder.verify(mMockNetd).networkCreatePhysical(workAgent.getNetwork().netId, - INetd.PERMISSION_SYSTEM); + inOrder.verify(mMockNetd).networkCreate( + nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM)); inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId, uidRangeFor(testHandle)); inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId, @@ -12054,8 +12114,8 @@ public class ConnectivityServiceTest { mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); mProfileDefaultNetworkCallback.assertNoCallback(); - inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId, - INetd.PERMISSION_NONE); + inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( + mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); // When the agent disconnects, test that the app on the work profile falls back to the // default network. @@ -12085,8 +12145,8 @@ public class ConnectivityServiceTest { mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent2); assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback); - inOrder.verify(mMockNetd).networkCreatePhysical(workAgent2.getNetwork().netId, - INetd.PERMISSION_SYSTEM); + inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( + workAgent2.getNetwork().netId, INetd.PERMISSION_SYSTEM)); inOrder.verify(mMockNetd).networkAddUidRanges(workAgent2.getNetwork().netId, uidRangeFor(testHandle)); @@ -12131,8 +12191,8 @@ public class ConnectivityServiceTest { mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE, r -> r.run(), listener); listener.expectOnComplete(); - inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId, - INetd.PERMISSION_NONE); + inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( + mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId, uidRangeFor(testHandle)); @@ -12184,10 +12244,10 @@ public class ConnectivityServiceTest { mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); app4Cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId, - INetd.PERMISSION_NONE); - inOrder.verify(mMockNetd).networkCreatePhysical(workAgent.getNetwork().netId, - INetd.PERMISSION_SYSTEM); + inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( + mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); + inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( + workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM)); final TestOnCompleteListener listener = new TestOnCompleteListener(); mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_ENTERPRISE, @@ -12239,8 +12299,8 @@ public class ConnectivityServiceTest { mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE, r -> r.run(), listener); listener.expectOnComplete(); - inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId, - INetd.PERMISSION_NONE); + inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical( + mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE)); inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle)); diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java index 32c95f149979..cf2c9c783ac7 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java @@ -16,9 +16,14 @@ package com.android.server; +import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_UP; +import static android.net.IpSecManager.DIRECTION_FWD; +import static android.net.IpSecManager.DIRECTION_IN; +import static android.net.IpSecManager.DIRECTION_OUT; +import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; @@ -56,6 +61,7 @@ import android.os.Binder; import android.os.ParcelFileDescriptor; import android.system.Os; import android.test.mock.MockContext; +import android.util.ArraySet; import androidx.test.filters.SmallTest; @@ -71,6 +77,7 @@ import java.net.Inet4Address; import java.net.Socket; import java.util.Arrays; import java.util.Collection; +import java.util.Set; /** Unit tests for {@link IpSecService}. */ @SmallTest @@ -119,7 +126,18 @@ public class IpSecServiceParameterizedTest { AppOpsManager mMockAppOps = mock(AppOpsManager.class); ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class); - MockContext mMockContext = new MockContext() { + TestContext mTestContext = new TestContext(); + + private class TestContext extends MockContext { + private Set<String> mAllowedPermissions = new ArraySet<>(Arrays.asList( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, + android.Manifest.permission.NETWORK_STACK, + PERMISSION_MAINLINE_NETWORK_STACK)); + + private void setAllowedPermissions(String... permissions) { + mAllowedPermissions = new ArraySet<>(permissions); + } + @Override public Object getSystemService(String name) { switch(name) { @@ -147,20 +165,22 @@ public class IpSecServiceParameterizedTest { @Override public void enforceCallingOrSelfPermission(String permission, String message) { - if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) { + if (mAllowedPermissions.contains(permission)) { return; + } else { + throw new SecurityException("Unavailable permission requested"); } - throw new SecurityException("Unavailable permission requested"); } @Override public int checkCallingOrSelfPermission(String permission) { - if (android.Manifest.permission.NETWORK_STACK.equals(permission)) { + if (mAllowedPermissions.contains(permission)) { return PERMISSION_GRANTED; + } else { + return PERMISSION_DENIED; } - throw new UnsupportedOperationException(); } - }; + } INetd mMockNetd; PackageManager mMockPkgMgr; @@ -194,7 +214,7 @@ public class IpSecServiceParameterizedTest { mMockNetd = mock(INetd.class); mMockPkgMgr = mock(PackageManager.class); mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class); - mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig); + mIpSecService = new IpSecService(mTestContext, mMockIpSecSrvConfig); // Injecting mock netd when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd); @@ -664,6 +684,21 @@ public class IpSecServiceParameterizedTest { assertNotNull(createTunnelResp); assertEquals(IpSecManager.Status.OK, createTunnelResp.status); + for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT, DIRECTION_FWD}) { + for (int selAddrFamily : ADDRESS_FAMILIES) { + verify(mMockNetd).ipSecAddSecurityPolicy( + eq(mUid), + eq(selAddrFamily), + eq(direction), + anyString(), + anyString(), + eq(0), + anyInt(), // iKey/oKey + anyInt(), // mask + eq(createTunnelResp.resourceId)); + } + } + return createTunnelResp; } @@ -798,16 +833,51 @@ public class IpSecServiceParameterizedTest { } @Test - public void testApplyTunnelModeTransform() throws Exception { - verifyApplyTunnelModeTransformCommon(false); + public void testApplyTunnelModeTransformOutbound() throws Exception { + verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT); } @Test - public void testApplyTunnelModeTransformReleasedSpi() throws Exception { - verifyApplyTunnelModeTransformCommon(true); + public void testApplyTunnelModeTransformOutboundNonNetworkStack() throws Exception { + mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS); + verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT); } - public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply) throws Exception { + @Test + public void testApplyTunnelModeTransformOutboundReleasedSpi() throws Exception { + verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_OUT); + } + + @Test + public void testApplyTunnelModeTransformInbound() throws Exception { + verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN); + } + + @Test + public void testApplyTunnelModeTransformInboundNonNetworkStack() throws Exception { + mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS); + verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN); + } + + @Test + public void testApplyTunnelModeTransformForward() throws Exception { + verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD); + } + + @Test + public void testApplyTunnelModeTransformForwardNonNetworkStack() throws Exception { + mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS); + + try { + verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD); + fail("Expected security exception due to use of forward policies without NETWORK_STACK" + + " or MAINLINE_NETWORK_STACK permission"); + } catch (SecurityException expected) { + } + } + + public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply, int direction) + throws Exception { IpSecConfig ipSecConfig = new IpSecConfig(); ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL); addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); @@ -825,17 +895,17 @@ public class IpSecServiceParameterizedTest { int transformResourceId = createTransformResp.resourceId; int tunnelResourceId = createTunnelResp.resourceId; mIpSecService.applyTunnelModeTransform( - tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE); + tunnelResourceId, direction, transformResourceId, BLESSED_PACKAGE); for (int selAddrFamily : ADDRESS_FAMILIES) { verify(mMockNetd) .ipSecUpdateSecurityPolicy( eq(mUid), eq(selAddrFamily), - eq(IpSecManager.DIRECTION_OUT), + eq(direction), anyString(), anyString(), - eq(TEST_SPI), + eq(direction == DIRECTION_OUT ? TEST_SPI : 0), anyInt(), // iKey/oKey anyInt(), // mask eq(tunnelResourceId)); diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java index 22a2c94fc194..22a2c94fc194 100644 --- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceTest.java index 6232423b4f9e..6232423b4f9e 100644 --- a/tests/net/java/com/android/server/IpSecServiceTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceTest.java diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt index 5ec111954fcc..5ec111954fcc 100644 --- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt +++ b/packages/Connectivity/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt diff --git a/tests/net/java/com/android/server/NetIdManagerTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/NetIdManagerTest.kt index 6f5e740d344c..6f5e740d344c 100644 --- a/tests/net/java/com/android/server/NetIdManagerTest.kt +++ b/packages/Connectivity/tests/unit/java/com/android/server/NetIdManagerTest.kt diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/NetworkManagementServiceTest.java index 13516d75a50d..13516d75a50d 100644 --- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/NetworkManagementServiceTest.java diff --git a/tests/net/java/com/android/server/NsdServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/NsdServiceTest.java index a90fa6882c25..a90fa6882c25 100644 --- a/tests/net/java/com/android/server/NsdServiceTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/NsdServiceTest.java diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java index 692c50fbef86..0ffeec98cf90 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java @@ -16,10 +16,10 @@ package com.android.server.connectivity; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER; import static android.net.NetworkCapabilities.MAX_TRANSPORT; import static android.net.NetworkCapabilities.MIN_TRANSPORT; @@ -44,6 +44,7 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivitySettingsManager; import android.net.IDnsResolver; import android.net.IpPrefix; import android.net.LinkAddress; @@ -187,9 +188,8 @@ public class DnsManagerTest { lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"), TEST_IFACENAME)); - Settings.Global.putString(mContentResolver, - PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); - Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com"); + ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); + ConnectivitySettingsManager.setPrivateDnsHostname(mCtx, "strictmode.com"); mDnsManager.updatePrivateDns(new Network(TEST_NETID), new PrivateDnsConfig("strictmode.com", new InetAddress[] { InetAddress.parseNumericAddress("6.6.6.6"), @@ -294,7 +294,7 @@ public class DnsManagerTest { assertNull(lp.getPrivateDnsServerName()); // Turn private DNS mode off - Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF); + ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_OFF); mDnsManager.updatePrivateDns(new Network(TEST_NETID), mDnsManager.getPrivateDnsConfig()); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); @@ -318,16 +318,15 @@ public class DnsManagerTest { assertEquals(new InetAddress[0], cfgAuto.ips); // Pretend a gservices push sets the default to "off". - Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off"); + ConnectivitySettingsManager.setPrivateDnsDefaultMode(mCtx, PRIVATE_DNS_MODE_OFF); final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mCtx); assertFalse(cfgOff.useTls); assertEquals("", cfgOff.hostname); assertEquals(new InetAddress[0], cfgOff.ips); // Strict mode still works. - Settings.Global.putString( - mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); - Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com"); + ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); + ConnectivitySettingsManager.setPrivateDnsHostname(mCtx, "strictmode.com"); final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mCtx); assertTrue(cfgStrict.useTls); assertEquals("strictmode.com", cfgStrict.hostname); diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt index eb3b4df1a282..eb3b4df1a282 100644 --- a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java index 70495cced536..70495cced536 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index 8b072c49de82..8b072c49de82 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java index 116d755e30a4..116d755e30a4 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java diff --git a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MetricsTestUtil.java index 5064b9bd91b9..5064b9bd91b9 100644 --- a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MetricsTestUtil.java diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java index 38f6d7f3172d..38f6d7f3172d 100644 --- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java index 9b2a638f8b39..9b2a638f8b39 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java index 50aaaee24418..50aaaee24418 100644 --- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java index 3adf08c19986..3adf08c19986 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java diff --git a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt index 86c91165f61b..86c91165f61b 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java index d7535a958117..c75618f43cde 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -30,6 +30,8 @@ import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; +import static android.net.ConnectivitySettingsManager.APPS_ALLOWED_ON_RESTRICTED_NETWORKS; +import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.Process.SYSTEM_UID; import static com.android.server.connectivity.PermissionMonitor.NETWORK; @@ -43,8 +45,10 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.AdditionalMatchers.aryEq; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -61,6 +65,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.database.ContentObserver; import android.net.INetd; import android.net.UidRange; import android.net.Uri; @@ -68,6 +73,7 @@ import android.os.Build; import android.os.SystemConfigManager; import android.os.UserHandle; import android.os.UserManager; +import android.util.ArraySet; import android.util.SparseIntArray; import androidx.test.InstrumentationRegistry; @@ -136,6 +142,7 @@ public class PermissionMonitorTest { final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext)); doReturn(UserHandle.ALL).when(asUserCtx).getUser(); when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx); + when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>()); mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps)); @@ -145,8 +152,15 @@ public class PermissionMonitorTest { private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid, String... permissions) { + return hasRestrictedNetworkPermission( + partition, targetSdkVersion, "" /* packageName */, uid, permissions); + } + + private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, + String packageName, int uid, String... permissions) { final PackageInfo packageInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition); + packageInfo.packageName = packageName; packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion; packageInfo.applicationInfo.uid = uid; return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo); @@ -280,6 +294,8 @@ public class PermissionMonitorTest { PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); assertFalse(hasRestrictedNetworkPermission( PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_P, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK)); assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1)); assertFalse(hasRestrictedNetworkPermission( @@ -324,6 +340,90 @@ public class PermissionMonitorTest { PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE)); } + @Test + public void testHasRestrictedNetworkPermissionAppAllowedOnRestrictedNetworks() { + mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks( + new ArraySet<>(new String[] { MOCK_PACKAGE1 })); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL)); + + assertFalse(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1)); + assertFalse(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE)); + assertFalse(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CONNECTIVITY_INTERNAL)); + + } + + private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) { + final PackageInfo packageInfo = packageInfoWithPermissions( + REQUESTED_PERMISSION_GRANTED, new String[] {}, partition); + packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion; + packageInfo.applicationInfo.uid = uid; + return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo); + } + + @Test + public void testIsCarryoverPackage() { + doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt(); + assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1)); + assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1)); + assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1)); + + doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt(); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1)); + assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1)); + + assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1)); + assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1)); + } + + private boolean wouldBeAppAllowedOnRestrictedNetworks(String packageName) { + final PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = packageName; + return mPermissionMonitor.isAppAllowedOnRestrictedNetworks(packageInfo); + } + + @Test + public void testIsAppAllowedOnRestrictedNetworks() { + mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(new ArraySet<>()); + assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1)); + assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2)); + + mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks( + new ArraySet<>(new String[] { MOCK_PACKAGE1 })); + assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1)); + assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2)); + + mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks( + new ArraySet<>(new String[] { MOCK_PACKAGE2 })); + assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1)); + assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2)); + + mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks( + new ArraySet<>(new String[] { "com.android.test" })); + assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1)); + assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2)); + } + private void assertBackgroundPermission(boolean hasPermission, String name, int uid, String... permissions) throws Exception { when(mPackageManager.getPackageInfo(eq(name), anyInt())) @@ -479,13 +579,14 @@ public class PermissionMonitorTest { public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception { when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( Arrays.asList(new PackageInfo[] { - buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1), - buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1), - buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1), - buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1) + buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1), + buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1), + buildPackageInfo(false /* hasSystemPermission */, MOCK_UID2, MOCK_USER1), + buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1) })); - when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn( - buildPackageInfo(false, MOCK_UID1, MOCK_USER1)); + when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), + eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( + buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1)); mPermissionMonitor.startMonitoring(); // Every app on user 0 except MOCK_UID2 are under VPN. final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] { @@ -530,11 +631,12 @@ public class PermissionMonitorTest { public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception { when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( Arrays.asList(new PackageInfo[] { - buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1), - buildPackageInfo(false, VPN_UID, MOCK_USER1) + buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1), + buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1) })); - when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn( - buildPackageInfo(false, MOCK_UID1, MOCK_USER1)); + when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), + eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( + buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1)); mPermissionMonitor.startMonitoring(); final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1)); @@ -798,4 +900,102 @@ public class PermissionMonitorTest { mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 }); } -} + @Test + public void testAppsAllowedOnRestrictedNetworksChanged() throws Exception { + final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService); + final ArgumentCaptor<ContentObserver> captor = + ArgumentCaptor.forClass(ContentObserver.class); + verify(mDeps, times(1)).registerContentObserver(any(), + argThat(uri -> uri.getEncodedPath().contains(APPS_ALLOWED_ON_RESTRICTED_NETWORKS)), + anyBoolean(), captor.capture()); + final ContentObserver contentObserver = captor.getValue(); + + mPermissionMonitor.onUserAdded(MOCK_USER1); + // Prepare PackageInfo for MOCK_PACKAGE1 + final PackageInfo packageInfo = buildPackageInfo( + false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1); + packageInfo.packageName = MOCK_PACKAGE1; + when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), anyInt())).thenReturn(packageInfo); + when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{MOCK_PACKAGE1}); + // Prepare PackageInfo for MOCK_PACKAGE2 + final PackageInfo packageInfo2 = buildPackageInfo( + false /* hasSystemPermission */, MOCK_UID2, MOCK_USER1); + packageInfo2.packageName = MOCK_PACKAGE2; + when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2); + when(mPackageManager.getPackagesForUid(MOCK_UID2)).thenReturn(new String[]{MOCK_PACKAGE2}); + + // MOCK_PACKAGE1 is listed in setting that allow to use restricted networks, MOCK_UID1 + // should have SYSTEM permission. + when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn( + new ArraySet<>(new String[] { MOCK_PACKAGE1 })); + contentObserver.onChange(true /* selfChange */); + mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1}); + mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2}); + + // MOCK_PACKAGE2 is listed in setting that allow to use restricted networks, MOCK_UID2 + // should have SYSTEM permission but MOCK_UID1 should revoke permission. + when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn( + new ArraySet<>(new String[] { MOCK_PACKAGE2 })); + contentObserver.onChange(true /* selfChange */); + mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2}); + mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1}); + + // No app lists in setting, should revoke permission from all uids. + when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>()); + contentObserver.onChange(true /* selfChange */); + mNetdMonitor.expectNoPermission( + new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1, MOCK_UID2}); + } + + @Test + public void testAppsAllowedOnRestrictedNetworksChangedWithSharedUid() throws Exception { + final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService); + final ArgumentCaptor<ContentObserver> captor = + ArgumentCaptor.forClass(ContentObserver.class); + verify(mDeps, times(1)).registerContentObserver(any(), + argThat(uri -> uri.getEncodedPath().contains(APPS_ALLOWED_ON_RESTRICTED_NETWORKS)), + anyBoolean(), captor.capture()); + final ContentObserver contentObserver = captor.getValue(); + + mPermissionMonitor.onUserAdded(MOCK_USER1); + // Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2 with shared uid MOCK_UID1. + final PackageInfo packageInfo = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE); + packageInfo.applicationInfo.uid = MOCK_USER1.getUid(MOCK_UID1); + packageInfo.packageName = MOCK_PACKAGE1; + final PackageInfo packageInfo2 = buildPackageInfo( + false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1); + packageInfo2.packageName = MOCK_PACKAGE2; + when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), anyInt())).thenReturn(packageInfo); + when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2); + when(mPackageManager.getPackagesForUid(MOCK_UID1)) + .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2}); + + // MOCK_PACKAGE1 have CHANGE_NETWORK_STATE, MOCK_UID1 should have NETWORK permission. + addPackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1); + mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1}); + + // MOCK_PACKAGE2 is listed in setting that allow to use restricted networks, MOCK_UID1 + // should upgrade to SYSTEM permission. + when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn( + new ArraySet<>(new String[] { MOCK_PACKAGE2 })); + contentObserver.onChange(true /* selfChange */); + mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1}); + + // MOCK_PACKAGE1 is listed in setting that allow to use restricted networks, MOCK_UID1 + // should still have SYSTEM permission. + when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn( + new ArraySet<>(new String[] { MOCK_PACKAGE1 })); + contentObserver.onChange(true /* selfChange */); + mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1}); + + // No app lists in setting, MOCK_UID1 should downgrade to NETWORK permission. + when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>()); + contentObserver.onChange(true /* selfChange */); + mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1}); + + // MOCK_PACKAGE1 removed, should revoke permission from MOCK_UID1. + when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{MOCK_PACKAGE2}); + removePackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1); + mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1}); + } +}
\ No newline at end of file diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/VpnTest.java index 6ad4900989f5..b725b826b14f 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/VpnTest.java @@ -1023,7 +1023,7 @@ public class VpnTest { assertNotNull(nc); VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo(); assertNotNull(ti); - assertEquals(type, ti.type); + assertEquals(type, ti.getType()); } public void startRacoon(final String serverAddr, final String expectedAddr) diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsAccessTest.java index 8b730af76951..8b730af76951 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsAccessTest.java diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsBaseTest.java index a058a466a4ff..a058a466a4ff 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsBaseTest.java diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsCollectionTest.java index 505ff9b6a34b..505ff9b6a34b 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsCollectionTest.java diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java index f3ae9b051e7c..f3ae9b051e7c 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java index 9fa1c50423d9..9fa1c50423d9 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java index 0ab4d2be4df1..fe2985c2ee54 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java @@ -45,6 +45,7 @@ import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; import static android.net.NetworkTemplate.OEM_MANAGED_NO; import static android.net.NetworkTemplate.OEM_MANAGED_YES; +import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateMobileWithRatType; import static android.net.NetworkTemplate.buildTemplateWifi; @@ -305,7 +306,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // verify service has empty history for wifi @@ -348,7 +349,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // verify service has empty history for wifi @@ -422,7 +423,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // modify some number on wifi, and trigger poll event @@ -463,7 +464,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // create some traffic on first network @@ -498,7 +499,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); forcePollAndWaitForIdle(); @@ -538,7 +539,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // create some traffic @@ -606,7 +607,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsUidDetail(buildEmptyStats()); setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Create some traffic. @@ -669,24 +670,28 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testMobileStatsOemManaged() throws Exception { final NetworkTemplate templateOemPaid = new NetworkTemplate(MATCH_MOBILE_WILDCARD, /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID, + SUBSCRIBER_ID_MATCH_RULE_EXACT); final NetworkTemplate templateOemPrivate = new NetworkTemplate(MATCH_MOBILE_WILDCARD, /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE, + SUBSCRIBER_ID_MATCH_RULE_EXACT); final NetworkTemplate templateOemAll = new NetworkTemplate(MATCH_MOBILE_WILDCARD, /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_PAID | OEM_PRIVATE); + OEM_PAID | OEM_PRIVATE, SUBSCRIBER_ID_MATCH_RULE_EXACT); final NetworkTemplate templateOemYes = new NetworkTemplate(MATCH_MOBILE_WILDCARD, /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES, + SUBSCRIBER_ID_MATCH_RULE_EXACT); final NetworkTemplate templateOemNone = new NetworkTemplate(MATCH_MOBILE_WILDCARD, /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO, + SUBSCRIBER_ID_MATCH_RULE_EXACT); // OEM_PAID network comes online. NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{ @@ -694,7 +699,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Create some traffic. @@ -709,7 +714,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Create some traffic. @@ -725,7 +730,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { NetworkCapabilities.NET_CAPABILITY_OEM_PAID})}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Create some traffic. @@ -739,7 +744,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Create some traffic. @@ -792,7 +797,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // create some traffic for two apps @@ -851,7 +856,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); NetworkStats.Entry entry1 = new NetworkStats.Entry( @@ -889,13 +894,13 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { final LinkProperties stackedProp = new LinkProperties(); stackedProp.setInterfaceName(stackedIface); final NetworkStateSnapshot wifiState = buildWifiState(); - wifiState.linkProperties.addStackedLink(stackedProp); + wifiState.getLinkProperties().addStackedLink(stackedProp); NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {wifiState}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); NetworkStats.Entry uidStats = new NetworkStats.Entry( @@ -926,7 +931,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // mStatsFactory#readNetworkStatsDetail() has the following invocations: // 1) NetworkStatsService#systemReady from #setUp. - // 2) mService#forceUpdateIfaces in the test above. + // 2) mService#notifyNetworkStatus in the test above. // // Additionally, we should have one call from the above call to mService#getDetailedUidStats // with the augmented ifaceFilter. @@ -950,7 +955,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // create some initial traffic @@ -1008,7 +1013,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // create some initial traffic @@ -1048,7 +1053,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Create some traffic @@ -1087,7 +1092,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // create some tethering traffic @@ -1144,7 +1149,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // verify service has empty history for wifi @@ -1250,7 +1255,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { mService.registerNetworkStatsProvider("TEST", provider); assertNotNull(cb); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Verifies that one requestStatsUpdate will be called during iface update. @@ -1315,7 +1320,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { mService.registerNetworkStatsProvider("TEST", provider); assertNotNull(cb); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Verifies that one requestStatsUpdate will be called during iface update. @@ -1373,7 +1378,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)}; - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Register custom provider and retrieve callback. @@ -1423,7 +1428,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // 3G network comes online. setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS); - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Create some traffic. @@ -1445,7 +1450,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { setCombineSubtypeEnabled(true); // Call handleOnCollapsedRatTypeChanged manually to simulate the callback fired - // when stopping monitor, this is needed by NetworkStatsService to trigger updateIfaces. + // when stopping monitor, this is needed by NetworkStatsService to trigger + // handleNotifyNetworkStatus. mService.handleOnCollapsedRatTypeChanged(); HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT); // Create some traffic. @@ -1494,7 +1500,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{ buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)}; expectNetworkStatsUidDetail(buildEmptyStats()); - mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), + mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); // Create some traffic on mobile network. @@ -1580,10 +1586,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { } private String getActiveIface(NetworkStateSnapshot... states) throws Exception { - if (states == null || states.length == 0 || states[0].linkProperties == null) { + if (states == null || states.length == 0 || states[0].getLinkProperties() == null) { return null; } - return states[0].linkProperties.getInterfaceName(); + return states[0].getLinkProperties().getInterfaceName(); } private void expectNetworkStatsSummary(NetworkStats summary) throws Exception { diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java index 6d2c7dc39ffd..6d2c7dc39ffd 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java index ebbc0ef62548..ebbc0ef62548 100644 --- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java +++ b/packages/Connectivity/tests/unit/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java diff --git a/tests/net/jni/Android.bp b/packages/Connectivity/tests/unit/jni/Android.bp index 22a04f5c0945..22a04f5c0945 100644 --- a/tests/net/jni/Android.bp +++ b/packages/Connectivity/tests/unit/jni/Android.bp diff --git a/tests/net/jni/test_onload.cpp b/packages/Connectivity/tests/unit/jni/test_onload.cpp index 5194ddb0d882..5194ddb0d882 100644 --- a/tests/net/jni/test_onload.cpp +++ b/packages/Connectivity/tests/unit/jni/test_onload.cpp diff --git a/tests/net/res/raw/history_v1 b/packages/Connectivity/tests/unit/res/raw/history_v1 Binary files differindex de79491c032e..de79491c032e 100644 --- a/tests/net/res/raw/history_v1 +++ b/packages/Connectivity/tests/unit/res/raw/history_v1 diff --git a/tests/net/res/raw/net_dev_typical b/packages/Connectivity/tests/unit/res/raw/net_dev_typical index 290bf03eb9b4..290bf03eb9b4 100644 --- a/tests/net/res/raw/net_dev_typical +++ b/packages/Connectivity/tests/unit/res/raw/net_dev_typical diff --git a/tests/net/res/raw/netstats_uid_v4 b/packages/Connectivity/tests/unit/res/raw/netstats_uid_v4 Binary files differindex e75fc1ca5c2e..e75fc1ca5c2e 100644 --- a/tests/net/res/raw/netstats_uid_v4 +++ b/packages/Connectivity/tests/unit/res/raw/netstats_uid_v4 diff --git a/tests/net/res/raw/netstats_v1 b/packages/Connectivity/tests/unit/res/raw/netstats_v1 Binary files differindex e80860a6b959..e80860a6b959 100644 --- a/tests/net/res/raw/netstats_v1 +++ b/packages/Connectivity/tests/unit/res/raw/netstats_v1 diff --git a/tests/net/res/raw/xt_qtaguid_iface_fmt_typical b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_fmt_typical index 656d5bb82da4..656d5bb82da4 100644 --- a/tests/net/res/raw/xt_qtaguid_iface_fmt_typical +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_fmt_typical diff --git a/tests/net/res/raw/xt_qtaguid_iface_typical b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_typical index 610723aef2f2..610723aef2f2 100644 --- a/tests/net/res/raw/xt_qtaguid_iface_typical +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_typical diff --git a/tests/net/res/raw/xt_qtaguid_typical b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_typical index c1b0d259955c..c1b0d259955c 100644 --- a/tests/net/res/raw/xt_qtaguid_typical +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_typical diff --git a/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_incorrect_iface index fc92715253ed..fc92715253ed 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_incorrect_iface diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying index 1ef18894b669..1ef18894b669 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_compression index 6d6bf550bbfa..6d6bf550bbfa 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_compression diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic index 2c2e5d2555f6..2c2e5d2555f6 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn index eb0513b10049..eb0513b10049 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn diff --git a/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_rewrite_through_self index afcdd7199026..afcdd7199026 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_rewrite_through_self diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_duplication index d7c7eb9f4ae8..d7c7eb9f4ae8 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_duplication diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split index 38a3dce4a834..38a3dce4a834 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split_compression index d35244b3b4f2..d35244b3b4f2 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split_compression diff --git a/tests/net/res/raw/xt_qtaguid_vpn_with_clat b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_with_clat index 0d893d515ca2..0d893d515ca2 100644 --- a/tests/net/res/raw/xt_qtaguid_vpn_with_clat +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_with_clat diff --git a/tests/net/res/raw/xt_qtaguid_with_clat b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat index f04b32f08332..f04b32f08332 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_after index 12d98ca29f57..12d98ca29f57 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_after diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_before index ce4bcc3a3b43..ce4bcc3a3b43 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_before diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_simple b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_simple index a1d6d411bad8..a1d6d411bad8 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat_simple +++ b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_simple diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 16a946dc7bc6..f8cb5d3d2419 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -561,7 +561,20 @@ public class DynamicSystemInstallationService extends Service break; } - Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail); + StringBuilder msg = new StringBuilder(); + msg.append("status: " + statusString + ", cause: " + causeString); + if (status == STATUS_IN_PROGRESS) { + msg.append( + String.format( + ", partition name: %s, progress: %d/%d", + mCurrentPartitionName, + mCurrentPartitionInstalledSize, + mCurrentPartitionSize)); + } + if (detail != null) { + msg.append(", detail: " + detail); + } + Log.d(TAG, msg.toString()); if (notifyOnNotificationBar) { mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail)); diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index 59ea9f0150bf..f18d4269c3ef 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -320,20 +320,21 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installScratch() throws IOException { - final long scratchSize = mDynSystem.suggestScratchSize(); + private void installWritablePartition(final String partitionName, final long partitionSize) + throws IOException { + Log.d(TAG, "Creating writable partition: " + partitionName + ", size: " + partitionSize); + Thread thread = new Thread() { @Override public void run() { mInstallationSession = - mDynSystem.createPartition("scratch", scratchSize, /* readOnly= */ false); + mDynSystem.createPartition( + partitionName, partitionSize, /* readOnly= */ false); } }; - Log.d(TAG, "Creating partition: scratch, size = " + scratchSize); thread.start(); - - Progress progress = new Progress("scratch", scratchSize, mNumInstalledPartitions++); + Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++); while (thread.isAlive()) { if (isCancelled()) { @@ -356,53 +357,22 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog if (mInstallationSession == null) { throw new IOException( - "Failed to start installation with requested size: " + scratchSize); + "Failed to start installation with requested size: " + partitionSize); } + // Reset installation session and verify that installation completes successfully. mInstallationSession = null; if (!mDynSystem.closePartition()) { - throw new IOException("Failed to complete partition installation: scratch"); + throw new IOException("Failed to complete partition installation: " + partitionName); } } - private void installUserdata() throws IOException { - Thread thread = new Thread(() -> { - mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false); - }); - - Log.d(TAG, "Creating partition: userdata, size = " + mUserdataSize); - thread.start(); - - Progress progress = new Progress("userdata", mUserdataSize, mNumInstalledPartitions++); - - while (thread.isAlive()) { - if (isCancelled()) { - return; - } - - final long installedSize = mDynSystem.getInstallationProgress().bytes_processed; - - if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) { - progress.installedSize = installedSize; - publishProgress(progress); - } - - try { - Thread.sleep(100); - } catch (InterruptedException e) { - // Ignore the error. - } - } + private void installScratch() throws IOException { + installWritablePartition("scratch", mDynSystem.suggestScratchSize()); + } - if (mInstallationSession == null) { - throw new IOException( - "Failed to start installation with requested size: " + mUserdataSize); - } - // Reset installation session and verify that installation completes successfully. - mInstallationSession = null; - if (!mDynSystem.closePartition()) { - throw new IOException("Failed to complete partition installation: userdata"); - } + private void installUserdata() throws IOException { + installWritablePartition("userdata", mUserdataSize); } private void installImages() throws IOException, ImageValidationException { diff --git a/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm b/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm index 2a95cfe6f8b1..16141883df98 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm @@ -85,14 +85,14 @@ key 8 { key 9 { label: '9' base: '\u0669' - shift: '(' + shift: ')' capslock: '9' } key 0 { label: '0' base: '\u0660' - shift: ')' + shift: '(' capslock: '0' } @@ -171,15 +171,15 @@ key P { } key LEFT_BRACKET { - label: '[' + label: ']' base, capslock: '\u062c' - shift: '<' + shift: '>' } key RIGHT_BRACKET { - label: ']' + label: '[' base, capslock: '\u062f' - shift: '>' + shift: '<' } key BACKSLASH { diff --git a/packages/InputDevices/res/raw/keyboard_layout_hebrew.kcm b/packages/InputDevices/res/raw/keyboard_layout_hebrew.kcm index cd3a4b959386..283cb4ef2081 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_hebrew.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_hebrew.kcm @@ -89,14 +89,14 @@ key 8 { key 9 { label: '9' base: '9' - shift: '(' + shift: ')' shift+capslock: '\u05c2' } key 0 { label: '0' base: '0' - shift: ')' + shift: '(' shift+capslock: '\u05c1' } @@ -180,17 +180,17 @@ key P { } key LEFT_BRACKET { - label: '[' - base, capslock: '[' - shift: '{' -} - -key RIGHT_BRACKET { label: ']' base, capslock: ']' shift: '}' } +key RIGHT_BRACKET { + label: '[' + base, capslock: '[' + shift: '{' +} + ### ROW 3 key A { @@ -322,14 +322,14 @@ key M { key COMMA { label: ',' base: '\u05ea' - shift: '<' + shift: '>' capslock: ',' } key PERIOD { label: '.' base: '\u05e5' - shift: '>' + shift: '<' capslock: '.' } diff --git a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm index e7dd6c6d68c8..bfe78212b1eb 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm @@ -292,14 +292,14 @@ key TAB { key COMMA { label, number: '\u0648' base: '\u0648' - shift: '<' + shift: '>' ctrl, alt, meta: none } key PERIOD { label, number: '.' base: '.' - shift: '>' + shift: '<' ctrl, alt, meta: none } @@ -440,14 +440,14 @@ key NUMPAD_9 { } key NUMPAD_LEFT_PAREN { - label, number: '(' - base: '(' + label, number: ')' + base: ')' ctrl, alt, meta: none } key NUMPAD_RIGHT_PAREN { - label, number: ')' - base: ')' + label, number: '(' + base: '(' ctrl, alt, meta: none } diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java index 60bcf37304a5..18c38c5a6494 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java @@ -113,7 +113,8 @@ public class DataUsageController { } public DataUsageInfo getWifiDataUsageInfo() { - NetworkTemplate template = NetworkTemplate.buildTemplateWifiWildcard(); + NetworkTemplate template = NetworkTemplate.buildTemplateWifi( + NetworkTemplate.WIFI_NETWORKID_ALL, null); return getDataUsageInfo(template); } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index bcabec858487..2c1d3e2af118 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -683,6 +683,16 @@ public class AccessPointTest { assertThat(ap.getTitle()).isEqualTo(providerFriendlyName); } + // This method doesn't copy mIsFailover, mIsAvailable and mIsRoaming because NetworkInfo + // doesn't expose those three set methods. But that's fine since the tests don't use those three + // variables. + private NetworkInfo copyNetworkInfo(NetworkInfo ni) { + final NetworkInfo copy = new NetworkInfo(ni.getType(), ni.getSubtype(), ni.getTypeName(), + ni.getSubtypeName()); + copy.setDetailedState(ni.getDetailedState(), ni.getReason(), ni.getExtraInfo()); + return copy; + } + @Test public void testUpdateNetworkInfo_returnsTrue() { int networkId = 123; @@ -704,7 +714,7 @@ public class AccessPointTest { .setWifiInfo(wifiInfo) .build(); - NetworkInfo newInfo = new NetworkInfo(networkInfo); + NetworkInfo newInfo = copyNetworkInfo(networkInfo); newInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", ""); assertThat(ap.update(config, wifiInfo, newInfo)).isTrue(); } @@ -730,7 +740,7 @@ public class AccessPointTest { .setWifiInfo(wifiInfo) .build(); - NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values + NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values assertThat(ap.update(config, wifiInfo, newInfo)).isFalse(); } @@ -755,7 +765,7 @@ public class AccessPointTest { .setWifiInfo(wifiInfo) .build(); - NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values + NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values wifiInfo.setRssi(rssi + 1); assertThat(ap.update(config, wifiInfo, newInfo)).isTrue(); } @@ -781,7 +791,7 @@ public class AccessPointTest { .setWifiInfo(wifiInfo) .build(); - NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values + NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values wifiInfo.setRssi(WifiInfo.INVALID_RSSI); assertThat(ap.update(config, wifiInfo, newInfo)).isFalse(); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java index f7bee30a087f..27d877db4952 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java @@ -89,7 +89,8 @@ public class DataUsageControllerTest { mNetworkTemplate = NetworkTemplate.buildTemplateMobileAll(SUB_ID); mNetworkTemplate2 = NetworkTemplate.buildTemplateMobileAll(SUB_ID_2); - mWifiNetworkTemplate = NetworkTemplate.buildTemplateWifiWildcard(); + mWifiNetworkTemplate = NetworkTemplate.buildTemplateWifi( + NetworkTemplate.WIFI_NETWORKID_ALL, null); } @Test diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 44864a61ade6..9cd7083a2a11 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -24,6 +24,7 @@ import android.app.backup.FullBackupDataOutput; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; +import android.content.pm.PackageManager; import android.database.Cursor; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; @@ -42,6 +43,7 @@ import android.provider.settings.validators.GlobalSettingsValidators; import android.provider.settings.validators.SecureSettingsValidators; import android.provider.settings.validators.SystemSettingsValidators; import android.provider.settings.validators.Validator; +import android.telephony.SubscriptionManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.BackupUtils; @@ -95,10 +97,11 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final String KEY_NETWORK_POLICIES = "network_policies"; private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config"; private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config"; + private static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings"; // Versioning of the state file. Increment this version // number any time the set of state items is altered. - private static final int STATE_VERSION = 8; + private static final int STATE_VERSION = 9; // Versioning of the Network Policies backup payload. private static final int NETWORK_POLICIES_BACKUP_VERSION = 1; @@ -106,19 +109,20 @@ public class SettingsBackupAgent extends BackupAgentHelper { // Slots in the checksum array. Never insert new items in the middle // of this array; new slots must be appended. - private static final int STATE_SYSTEM = 0; - private static final int STATE_SECURE = 1; - private static final int STATE_LOCALE = 2; - private static final int STATE_WIFI_SUPPLICANT = 3; - private static final int STATE_WIFI_CONFIG = 4; - private static final int STATE_GLOBAL = 5; - private static final int STATE_LOCK_SETTINGS = 6; - private static final int STATE_SOFTAP_CONFIG = 7; - private static final int STATE_NETWORK_POLICIES = 8; - private static final int STATE_WIFI_NEW_CONFIG = 9; - private static final int STATE_DEVICE_CONFIG = 10; - - private static final int STATE_SIZE = 11; // The current number of state items + private static final int STATE_SYSTEM = 0; + private static final int STATE_SECURE = 1; + private static final int STATE_LOCALE = 2; + private static final int STATE_WIFI_SUPPLICANT = 3; + private static final int STATE_WIFI_CONFIG = 4; + private static final int STATE_GLOBAL = 5; + private static final int STATE_LOCK_SETTINGS = 6; + private static final int STATE_SOFTAP_CONFIG = 7; + private static final int STATE_NETWORK_POLICIES = 8; + private static final int STATE_WIFI_NEW_CONFIG = 9; + private static final int STATE_DEVICE_CONFIG = 10; + private static final int STATE_SIM_SPECIFIC_SETTINGS = 11; + + private static final int STATE_SIZE = 12; // The current number of state items // Number of entries in the checksum array at various version numbers private static final int STATE_SIZES[] = { @@ -130,7 +134,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { 8, // version 5 added STATE_SOFTAP_CONFIG 9, // version 6 added STATE_NETWORK_POLICIES 10, // version 7 added STATE_WIFI_NEW_CONFIG - STATE_SIZE // version 8 added STATE_DEVICE_CONFIG + 11, // version 8 added STATE_DEVICE_CONFIG + STATE_SIZE // version 9 added STATE_SIM_SPECIFIC_SETTINGS }; private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry @@ -208,7 +213,6 @@ public class SettingsBackupAgent extends BackupAgentHelper { @Override public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException { - byte[] systemSettingsData = getSystemSettings(); byte[] secureSettingsData = getSecureSettings(); byte[] globalSettingsData = getGlobalSettings(); @@ -218,6 +222,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { byte[] netPoliciesData = getNetworkPolicies(); byte[] wifiFullConfigData = getNewWifiConfigData(); byte[] deviceSpecificInformation = getDeviceSpecificConfiguration(); + byte[] simSpecificSettingsData = getSimSpecificSettingsData(); long[] stateChecksums = readOldChecksums(oldState); @@ -246,6 +251,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { stateChecksums[STATE_DEVICE_CONFIG] = writeIfChanged(stateChecksums[STATE_DEVICE_CONFIG], KEY_DEVICE_SPECIFIC_CONFIG, deviceSpecificInformation, data); + stateChecksums[STATE_SIM_SPECIFIC_SETTINGS] = + writeIfChanged(stateChecksums[STATE_SIM_SPECIFIC_SETTINGS], + KEY_SIM_SPECIFIC_SETTINGS, simSpecificSettingsData, data); writeNewChecksums(stateChecksums, newState); } @@ -386,6 +394,12 @@ public class SettingsBackupAgent extends BackupAgentHelper { preservedSettings); break; + case KEY_SIM_SPECIFIC_SETTINGS: + byte[] restoredSimSpecificSettings = new byte[size]; + data.readEntityData(restoredSimSpecificSettings, 0, size); + restoreSimSpecificSettings(restoredSimSpecificSettings); + break; + default : data.skipEntityData(); @@ -1189,6 +1203,28 @@ public class SettingsBackupAgent extends BackupAgentHelper { return true; } + private byte[] getSimSpecificSettingsData() { + byte[] simSpecificData = new byte[0]; + PackageManager packageManager = getBaseContext().getPackageManager(); + if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { + SubscriptionManager subManager = SubscriptionManager.from(getBaseContext()); + simSpecificData = subManager.getAllSimSpecificSettingsForBackup(); + Log.i(TAG, "sim specific data of length + " + simSpecificData.length + + " successfully retrieved"); + } + + return simSpecificData; + } + + private void restoreSimSpecificSettings(byte[] data) { + PackageManager packageManager = getBaseContext().getPackageManager(); + boolean hasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); + if (hasTelephony) { + SubscriptionManager subManager = SubscriptionManager.from(getBaseContext()); + subManager.restoreAllSimSpecificSettingsFromBackup(data); + } + } + private void updateWindowManagerIfNeeded(Integer previousDensity) { int newDensity; try { diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 4a64d6b2ff95..2a12ce2854b6 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -155,6 +155,7 @@ <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <!-- TODO(b/152310230): remove once APIs are confirmed to be sufficient --> <uses-permission android:name="com.android.permission.USE_INSTALLER_V2" /> + <uses-permission android:name="android.permission.INSTALL_TEST_ONLY_PACKAGE" /> <uses-permission android:name="android.permission.MOVE_PACKAGE" /> <uses-permission android:name="android.permission.KEEP_UNINSTALLED_PACKAGES" /> <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /> @@ -466,6 +467,9 @@ <!-- Permission required for CTS test - CtsAlarmManagerTestCases --> <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" /> + <!-- Permission required for CTS test - GlobalSearchSessionPlatformCtsTests --> + <uses-permission android:name="android.permission.READ_GLOBAL_APP_SEARCH_DATA" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS b/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS index 8765c9a64b77..947466f3baaf 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS @@ -1,7 +1,3 @@ set noparent -kchyn@google.com -jaggies@google.com -curtislb@google.com -ilyamaty@google.com -joshmccloskey@google.com +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 583953ce34af..50437240a29f 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -80,6 +80,7 @@ public class PipBoundsHandler { private int mImeHeight; private boolean mIsShelfShowing; private int mShelfHeight; + private boolean mDefaultLandscape; private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener = new DisplayController.OnDisplaysChangedListener() { @@ -87,6 +88,7 @@ public class PipBoundsHandler { public void onDisplayAdded(int displayId) { if (displayId == mContext.getDisplayId()) { mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId)); + mDefaultLandscape = (mDisplayInfo.logicalWidth > mDisplayInfo.logicalHeight); } } }; @@ -362,9 +364,17 @@ public class PipBoundsHandler { private void updateDisplayInfoIfNeeded() { final boolean updateNeeded; if ((mDisplayInfo.rotation == ROTATION_0) || (mDisplayInfo.rotation == ROTATION_180)) { - updateNeeded = (mDisplayInfo.logicalWidth > mDisplayInfo.logicalHeight); + if (!mDefaultLandscape) { + updateNeeded = (mDisplayInfo.logicalWidth > mDisplayInfo.logicalHeight); + } else { + updateNeeded = (mDisplayInfo.logicalWidth < mDisplayInfo.logicalHeight); + } } else { - updateNeeded = (mDisplayInfo.logicalWidth < mDisplayInfo.logicalHeight); + if (!mDefaultLandscape) { + updateNeeded = (mDisplayInfo.logicalWidth < mDisplayInfo.logicalHeight); + } else { + updateNeeded = (mDisplayInfo.logicalWidth > mDisplayInfo.logicalHeight); + } } if (updateNeeded) { final int newLogicalHeight = mDisplayInfo.logicalWidth; diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 54df53dbe6d7..29d77a72c73a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -45,6 +45,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.util.EventLog; import android.util.Log; import android.util.Size; import android.view.SurfaceControl; @@ -223,6 +224,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; private PictureInPictureParams mPictureInPictureParams; + private int mOverridableMinSize; /** * If set to {@code true}, the entering animation will be skipped and we will wait for @@ -244,6 +246,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements mPipBoundsHandler = boundsHandler; mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); + mOverridableMinSize = context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.overridable_minimal_size_pip_resizable_task); mSurfaceTransactionHelper = surfaceTransactionHelper; mPipAnimationController = pipAnimationController; mPipUiEventLoggerLogger = pipUiEventLogger; @@ -949,7 +953,14 @@ public class PipTaskOrganizer extends TaskOrganizer implements // -1 will be populated if an activity specifies defaultWidth/defaultHeight in <layout> // without minWidth/minHeight if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) { - return new Size(windowLayout.minWidth, windowLayout.minHeight); + // If either dimension is smaller than the allowed minimum, adjust them + // according to mOverridableMinSize and log to SafeNet + if (windowLayout.minWidth < mOverridableMinSize + || windowLayout.minHeight < mOverridableMinSize) { + EventLog.writeEvent(0x534e4554, "174302616", -1, ""); + } + return new Size(Math.max(windowLayout.minWidth, mOverridableMinSize), + Math.max(windowLayout.minHeight, mOverridableMinSize)); } return null; } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java index 42dde4064a97..b8a468e0ce45 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java @@ -252,7 +252,7 @@ public class ScreenshotNotificationsController { dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); if (intent != null) { final PendingIntent pendingIntent = PendingIntent.getActivityAsUser( - mContext, 0, intent, 0, null, UserHandle.CURRENT); + mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT); b.setContentIntent(pendingIntent); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index 60ee75b534d8..f6f8d6c7f4a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -193,7 +193,8 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof if (enabled) { mWaitingForTerminalState = true; if (DEBUG) Log.d(TAG, "Starting tethering"); - mTetheringManager.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + mTetheringManager.startTethering(new TetheringRequest.Builder( + TETHERING_WIFI).setShouldShowEntitlementUi(false).build(), ConcurrentUtils.DIRECT_EXECUTOR, new TetheringManager.StartTetheringCallback() { @Override diff --git a/services/Android.bp b/services/Android.bp index 0a01c955a612..1f4258dce312 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -146,79 +146,23 @@ stubs_defaults { " --hide-package com.google.android.startop.iorap" + " --hide DeprecationMismatch" + " --hide HiddenTypedefConstant", - visibility: ["//visibility:private"], + visibility: ["//frameworks/base:__subpackages__"], filter_packages: ["com.android."], } droidstubs { - name: "services-stubs.sources", - srcs: [":services-all-sources"], + name: "services-non-updatable-stubs", + srcs: [":services-non-updatable-sources"], defaults: ["services-stubs-default"], check_api: { current: { api_file: "api/current.txt", removed_api_file: "api/removed.txt", }, - last_released: { - api_file: ":android.api.system-server.latest", - removed_api_file: ":removed.api.system-server.latest", - baseline_file: ":android-incompatibilities.api.system-server.latest", - }, - api_lint: { - enabled: true, - new_since: ":android.api.system-server.latest", - baseline_file: "api/lint-baseline.txt", - }, - }, - dists: [ - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/system-server/api", - dest: "android.txt", - tag: ".api.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/system-server/api", - dest: "removed.txt", - tag: ".removed-api.txt", - }, - ], -} - -java_library { - name: "android_system_server_stubs_current", - defaults: ["android_stubs_dists_default"], - srcs: [":services-stubs.sources"], - installable: false, - static_libs: ["android_module_lib_stubs_current"], - sdk_version: "none", - system_modules: "none", - java_version: "1.8", - dist: { - dir: "apistubs/android/system-server", - }, -} - -droidstubs { - name: "services-non-updatable-stubs.sources", - srcs: [":services-non-updatable-sources"], - defaults: ["services-stubs-default"], - check_api: { - current: { - api_file: "api/non-updatable-current.txt", - removed_api_file: "api/non-updatable-removed.txt", - }, api_lint: { enabled: true, new_since: ":android-non-updatable.api.system-server.latest", - baseline_file: "api/non-updatable-lint-baseline.txt", + baseline_file: "api/lint-baseline.txt", }, }, dists: [ diff --git a/services/api/Android.bp b/services/api/Android.bp index bbc8c72b2eef..ee7d49fc99c8 100644 --- a/services/api/Android.bp +++ b/services/api/Android.bp @@ -24,12 +24,12 @@ package { filegroup { name: "non-updatable-system-server-current.txt", - srcs: ["non-updatable-current.txt"], + srcs: ["current.txt"], visibility: ["//frameworks/base/api"], } filegroup { name: "non-updatable-system-server-removed.txt", - srcs: ["non-updatable-removed.txt"], + srcs: ["removed.txt"], visibility: ["//frameworks/base/api"], } diff --git a/services/api/current.txt b/services/api/current.txt index 7c5c01ef6868..6419b7088fdb 100644 --- a/services/api/current.txt +++ b/services/api/current.txt @@ -1,49 +1,4 @@ // Signature format: 2.0 -package com.android.permission.persistence { - - public interface RuntimePermissionsPersistence { - method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance(); - method public void deleteForUser(@NonNull android.os.UserHandle); - method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle); - method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle); - } - - public final class RuntimePermissionsState { - ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>); - method @Nullable public String getFingerprint(); - method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions(); - method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions(); - method public int getVersion(); - field public static final int NO_VERSION = -1; // 0xffffffff - } - - public static final class RuntimePermissionsState.PermissionState { - ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int); - method public int getFlags(); - method @NonNull public String getName(); - method public boolean isGranted(); - } - -} - -package com.android.role.persistence { - - public interface RolesPersistence { - method @NonNull public static com.android.role.persistence.RolesPersistence createInstance(); - method public void deleteForUser(@NonNull android.os.UserHandle); - method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle); - method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle); - } - - public final class RolesState { - ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>); - method @Nullable public String getPackagesHash(); - method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles(); - method public int getVersion(); - } - -} - package com.android.server { public final class LocalManagerRegistry { diff --git a/services/api/lint-baseline.txt b/services/api/lint-baseline.txt index e985ddb5352b..b46d21edd44c 100644 --- a/services/api/lint-baseline.txt +++ b/services/api/lint-baseline.txt @@ -1,4 +1,8 @@ // Baseline format: 1.0 +NotCloseable: com.android.server.wifi.SupplicantManager: + Classes that release resources (stop()) should implement AutoClosable and CloseGuard: class com.android.server.wifi.SupplicantManager + + ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder): Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)} ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean): diff --git a/services/api/non-updatable-current.txt b/services/api/non-updatable-current.txt deleted file mode 100644 index 6419b7088fdb..000000000000 --- a/services/api/non-updatable-current.txt +++ /dev/null @@ -1,54 +0,0 @@ -// Signature format: 2.0 -package com.android.server { - - public final class LocalManagerRegistry { - method public static <T> void addManager(@NonNull Class<T>, @NonNull T); - method @Nullable public static <T> T getManager(@NonNull Class<T>); - } - - public abstract class SystemService { - ctor public SystemService(@NonNull android.content.Context); - method @NonNull public final android.content.Context getContext(); - method public boolean isUserSupported(@NonNull com.android.server.SystemService.TargetUser); - method public void onBootPhase(int); - method public abstract void onStart(); - method public void onUserStarting(@NonNull com.android.server.SystemService.TargetUser); - method public void onUserStopped(@NonNull com.android.server.SystemService.TargetUser); - method public void onUserStopping(@NonNull com.android.server.SystemService.TargetUser); - method public void onUserSwitching(@Nullable com.android.server.SystemService.TargetUser, @NonNull com.android.server.SystemService.TargetUser); - method public void onUserUnlocked(@NonNull com.android.server.SystemService.TargetUser); - method public void onUserUnlocking(@NonNull com.android.server.SystemService.TargetUser); - method protected final void publishBinderService(@NonNull String, @NonNull android.os.IBinder); - method protected final void publishBinderService(@NonNull String, @NonNull android.os.IBinder, boolean); - field public static final int PHASE_ACTIVITY_MANAGER_READY = 550; // 0x226 - field public static final int PHASE_BOOT_COMPLETED = 1000; // 0x3e8 - field public static final int PHASE_DEVICE_SPECIFIC_SERVICES_READY = 520; // 0x208 - field public static final int PHASE_LOCK_SETTINGS_READY = 480; // 0x1e0 - field public static final int PHASE_SYSTEM_SERVICES_READY = 500; // 0x1f4 - field public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600; // 0x258 - field public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // 0x64 - } - - public static final class SystemService.TargetUser { - method @NonNull public android.os.UserHandle getUserHandle(); - } - -} - -package com.android.server.stats { - - public final class StatsHelper { - method public static void sendStatsdReadyBroadcast(@NonNull android.content.Context); - } - -} - -package com.android.server.wifi { - - public class SupplicantManager { - method public static void start(); - method public static void stop(); - } - -} - diff --git a/services/api/non-updatable-lint-baseline.txt b/services/api/non-updatable-lint-baseline.txt deleted file mode 100644 index b46d21edd44c..000000000000 --- a/services/api/non-updatable-lint-baseline.txt +++ /dev/null @@ -1,9 +0,0 @@ -// Baseline format: 1.0 -NotCloseable: com.android.server.wifi.SupplicantManager: - Classes that release resources (stop()) should implement AutoClosable and CloseGuard: class com.android.server.wifi.SupplicantManager - - -ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder): - Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)} -ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean): - Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder,boolean)} diff --git a/services/api/non-updatable-removed.txt b/services/api/non-updatable-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/services/api/non-updatable-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/services/core/Android.bp b/services/core/Android.bp index 0ac8f74ff831..706f738d754d 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -10,7 +10,6 @@ package { filegroup { name: "services.core-sources", srcs: ["java/**/*.java"], - exclude_srcs: [":connectivity-service-srcs"], path: "java", visibility: ["//frameworks/base/services"], } @@ -200,29 +199,3 @@ prebuilt_etc { src: ":services.core.json.gz", } -// TODO: Move connectivity service sources to independent directory. -filegroup { - name: "connectivity-service-srcs", - srcs: [ - "java/com/android/server/ConnectivityService.java", - "java/com/android/server/ConnectivityServiceInitializer.java", - "java/com/android/server/TestNetworkService.java", - "java/com/android/server/connectivity/AutodestructReference.java", - "java/com/android/server/connectivity/ConnectivityConstants.java", - "java/com/android/server/connectivity/DnsManager.java", - "java/com/android/server/connectivity/FullScore.java", - "java/com/android/server/connectivity/KeepaliveTracker.java", - "java/com/android/server/connectivity/LingerMonitor.java", - "java/com/android/server/connectivity/MockableSystemProperties.java", - "java/com/android/server/connectivity/Nat464Xlat.java", - "java/com/android/server/connectivity/NetworkAgentInfo.java", - "java/com/android/server/connectivity/NetworkDiagnostics.java", - "java/com/android/server/connectivity/NetworkNotificationManager.java", - "java/com/android/server/connectivity/NetworkRanker.java", - "java/com/android/server/connectivity/PermissionMonitor.java", - "java/com/android/server/connectivity/ProxyTracker.java", - "java/com/android/server/connectivity/QosCallbackAgentConnection.java", - "java/com/android/server/connectivity/QosCallbackTracker.java", - "java/com/android/server/connectivity/TcpKeepaliveController.java", - ], -} diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index c771eb701b1d..f4a8f372bc36 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -40,6 +40,7 @@ import com.android.internal.os.AppIdToPackageMap; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderInternal; +import com.android.internal.os.BinderLatencyObserver; import com.android.internal.os.CachedDeviceState; import com.android.internal.util.DumpUtils; @@ -120,6 +121,7 @@ public class BinderCallsStatsService extends Binder { /** Listens for flag changes. */ private static class SettingsObserver extends ContentObserver { + // Settings for BinderCallsStats. private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking"; private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data"; @@ -127,6 +129,16 @@ public class BinderCallsStatsService extends Binder { private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid"; private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count"; + // Settings for BinderLatencyObserver. + private static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data"; + private static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY = + "latency_observer_sampling_interval"; + private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY = + "latency_histogram_bucket_count"; + private static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY = + "latency_histogram_first_bucket_size"; + private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY = + "latency_histogram_bucket_scale_factor"; private boolean mEnabled; private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS); @@ -180,6 +192,24 @@ public class BinderCallsStatsService extends Binder { mBinderCallsStats.setTrackDirectCallerUid( mParser.getBoolean(SETTINGS_TRACK_DIRECT_CALLING_UID_KEY, BinderCallsStats.DEFAULT_TRACK_DIRECT_CALLING_UID)); + mBinderCallsStats.setCollectLatencyData( + mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY, + BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA)); + // Binder latency observer settings. + BinderLatencyObserver binderLatencyObserver = mBinderCallsStats.getLatencyObserver(); + binderLatencyObserver.setSamplingInterval(mParser.getInt( + SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY, + BinderLatencyObserver.PERIODIC_SAMPLING_INTERVAL_DEFAULT)); + binderLatencyObserver.setHistogramBucketsParams( + mParser.getInt( + SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY, + BinderLatencyObserver.BUCKET_COUNT_DEFAULT), + mParser.getInt( + SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY, + BinderLatencyObserver.FIRST_BUCKET_SIZE_DEFAULT), + mParser.getFloat( + SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY, + BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT)); final boolean enabled = @@ -198,6 +228,7 @@ public class BinderCallsStatsService extends Binder { mEnabled = enabled; mBinderCallsStats.reset(); mBinderCallsStats.setAddDebugEntries(enabled); + mBinderCallsStats.getLatencyObserver().reset(); } } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 794cb9301d69..d6ee95131ea9 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -49,6 +49,7 @@ import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.system.ErrnoException; @@ -65,6 +66,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import com.android.net.module.util.NetdUtils; +import com.android.net.module.util.PermissionUtils; import libcore.io.IoUtils; @@ -466,8 +468,7 @@ public class IpSecService extends IIpSecService.Stub { /** Safety method; guards against access of other user's UserRecords */ private void checkCallerUid(int uid) { - if (uid != Binder.getCallingUid() - && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) { + if (uid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()) { throw new SecurityException("Attempted access of unowned resources"); } } @@ -1105,11 +1106,15 @@ public class IpSecService extends IIpSecService.Stub { * Checks the user-provided direction field and throws an IllegalArgumentException if it is not * DIRECTION_IN or DIRECTION_OUT */ - private static void checkDirection(int direction) { + private void checkDirection(int direction) { switch (direction) { case IpSecManager.DIRECTION_OUT: case IpSecManager.DIRECTION_IN: return; + case IpSecManager.DIRECTION_FWD: + // Only NETWORK_STACK or MAINLINE_NETWORK_STACK allowed to use forward policies + PermissionUtils.enforceNetworkStackPermission(mContext); + return; } throw new IllegalArgumentException("Invalid Direction: " + direction); } @@ -1353,6 +1358,26 @@ public class IpSecService extends IIpSecService.Stub { ikey, 0xffffffff, resourceId); + + // Add a forwarding policy on the tunnel interface. In order to support forwarding + // the IpSecTunnelInterface must have a forwarding policy matching the incoming SA. + // + // Unless a IpSecTransform is also applied against this interface in DIRECTION_FWD, + // forwarding will be blocked by default (as would be the case if this policy was + // absent). + // + // This is necessary only on the tunnel interface, and not any the interface to + // which traffic will be forwarded to. + netd.ipSecAddSecurityPolicy( + callerUid, + selAddrFamily, + IpSecManager.DIRECTION_FWD, + remoteAddr, + localAddr, + 0, + ikey, + 0xffffffff, + resourceId); } userRecord.mTunnelInterfaceRecords.put( @@ -1820,7 +1845,7 @@ public class IpSecService extends IIpSecService.Stub { int mark = (direction == IpSecManager.DIRECTION_OUT) ? tunnelInterfaceInfo.getOkey() - : tunnelInterfaceInfo.getIkey(); + : tunnelInterfaceInfo.getIkey(); // Ikey also used for FWD policies try { // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 55e1b46a51a9..4ab947d93f70 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -32,8 +32,9 @@ per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo per-file IpSecService.java = file:/services/core/java/com/android/server/net/OWNERS per-file MmsServiceBroker.java = file:/telephony/OWNERS per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS -per-file PackageWatchdog.java = file:/services/core/java/com/android/server/rollback/OWNERS +per-file PackageWatchdog.java, RescueParty.java = file:/services/core/java/com/android/server/rollback/OWNERS per-file PinnerService.java = file:/apct-tests/perftests/OWNERS +per-file RescueParty.java = fdunlap@google.com, shuc@google.com per-file TelephonyRegistry.java = file:/telephony/OWNERS per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS per-file VcnManagementService.java = file:/services/core/java/com/android/server/vcn/OWNERS diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index d9ecddae558a..8084de856031 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -2873,6 +2873,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // If we're enforcing fine starting in Q, we also want to enforce coarse even for // older SDK versions. locationQueryBuilder.setMinSdkVersionForCoarse(0); + locationQueryBuilder.setMinSdkVersionForCoarse(0); + locationQueryBuilder.setMinSdkVersionForEnforcement(0); shouldCheckLocationPermissions = true; } @@ -3001,6 +3003,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + private boolean checkFineLocationAccess(Record r) { + return checkFineLocationAccess(r, Build.VERSION_CODES.BASE); + } + + private boolean checkCoarseLocationAccess(Record r) { + return checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE); + } + /** * Note -- this method should only be used at the site of a permission check if you need to * explicitly allow apps below a certain SDK level access regardless of location permissions. @@ -3016,6 +3026,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { .setMethod("TelephonyRegistry push") .setLogAsInfo(true) // we don't need to log an error every time we push .setMinSdkVersionForFine(minSdk) + .setMinSdkVersionForCoarse(minSdk) + .setMinSdkVersionForEnforcement(minSdk) .build(); return Binder.withCleanCallingIdentity(() -> { @@ -3040,6 +3052,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { .setMethod("TelephonyRegistry push") .setLogAsInfo(true) // we don't need to log an error every time we push .setMinSdkVersionForCoarse(minSdk) + .setMinSdkVersionForFine(Integer.MAX_VALUE) + .setMinSdkVersionForEnforcement(minSdk) .build(); return Binder.withCleanCallingIdentity(() -> { diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 45eb77453dbd..bcbd692a2f7d 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -87,6 +87,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -166,7 +167,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final VcnNetworkProvider mNetworkProvider; @NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb; @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker; - @NonNull private final VcnContext mVcnContext; @NonNull private final BroadcastReceiver mPkgChangeReceiver; @NonNull @@ -211,7 +211,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { mContext, mLooper, mTelephonySubscriptionTrackerCb); mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE); - mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider); mPkgChangeReceiver = new BroadcastReceiver() { @Override @@ -335,8 +334,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { public VcnContext newVcnContext( @NonNull Context context, @NonNull Looper looper, - @NonNull VcnNetworkProvider vcnNetworkProvider) { - return new VcnContext(context, looper, vcnNetworkProvider); + @NonNull VcnNetworkProvider vcnNetworkProvider, + boolean isInTestMode) { + return new VcnContext(context, looper, vcnNetworkProvider, isInTestMode); } /** Creates a new Vcn instance using the provided configuration */ @@ -420,6 +420,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { "Carrier privilege required for subscription group to set VCN Config"); } + private void enforceManageTestNetworksForTestMode(@NonNull VcnConfig vcnConfig) { + if (vcnConfig.isTestModeProfile()) { + mContext.enforceCallingPermission( + android.Manifest.permission.MANAGE_TEST_NETWORKS, + "Test-mode require the MANAGE_TEST_NETWORKS permission"); + } + } + private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback { /** * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker} @@ -431,7 +439,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { // Startup VCN instances synchronized (mLock) { + final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; mLastSnapshot = snapshot; + Slog.d(TAG, "new snapshot: " + mLastSnapshot); // Start any VCN instances as necessary for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) { @@ -478,11 +488,29 @@ public class VcnManagementService extends IVcnManagementService.Stub { entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); } } + + final Map<ParcelUuid, Set<Integer>> oldSubGrpMappings = + getSubGroupToSubIdMappings(oldSnapshot); + final Map<ParcelUuid, Set<Integer>> currSubGrpMappings = + getSubGroupToSubIdMappings(mLastSnapshot); + if (!currSubGrpMappings.equals(oldSubGrpMappings)) { + notifyAllPolicyListenersLocked(); + } } } } @GuardedBy("mLock") + private Map<ParcelUuid, Set<Integer>> getSubGroupToSubIdMappings( + @NonNull TelephonySubscriptionSnapshot snapshot) { + final Map<ParcelUuid, Set<Integer>> subGrpMappings = new ArrayMap<>(); + for (ParcelUuid subGrp : mVcns.keySet()) { + subGrpMappings.put(subGrp, snapshot.getAllSubIdsInGroup(subGrp)); + } + return subGrpMappings; + } + + @GuardedBy("mLock") private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) { final Vcn vcnToTeardown = mVcns.remove(uuidToTeardown); if (vcnToTeardown == null) { @@ -516,15 +544,18 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); + Slog.d(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active // VCN. final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup); + final VcnContext vcnContext = + mDeps.newVcnContext( + mContext, mLooper, mNetworkProvider, config.isTestModeProfile()); final Vcn newInstance = - mDeps.newVcn(mVcnContext, subscriptionGroup, config, mLastSnapshot, vcnCallback); + mDeps.newVcn(vcnContext, subscriptionGroup, config, mLastSnapshot, vcnCallback); mVcns.put(subscriptionGroup, newInstance); // Now that a new VCN has started, notify all registered listeners to refresh their @@ -538,7 +569,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startOrUpdateVcnLocked( @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - Slog.v(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); + Slog.d(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); if (mVcns.containsKey(subscriptionGroup)) { final Vcn vcn = mVcns.get(subscriptionGroup); @@ -564,10 +595,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!config.getProvisioningPackageName().equals(opPkgName)) { throw new IllegalArgumentException("Mismatched caller and VcnConfig creator"); } - Slog.v(TAG, "VCN config updated for subGrp: " + subscriptionGroup); + Slog.d(TAG, "VCN config updated for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); + enforceManageTestNetworksForTestMode(config); enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { @@ -589,7 +621,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(opPkgName, "opPkgName was null"); - Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); + Slog.d(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), opPkgName); @@ -815,6 +847,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (isVcnManagedNetwork) { ncBuilder.removeCapability( NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } else { + ncBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); } if (isRestrictedCarrierWifi) { @@ -823,8 +857,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { } final NetworkCapabilities result = ncBuilder.build(); - return new VcnUnderlyingNetworkPolicy( + final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy( mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result); + + if (VDBG) { + Slog.d(TAG, "getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities + + "; and lp: " + linkProperties + "; result = " + policy); + } + return policy; }); } diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index d756c1ffd00f..26ecee8f21ab 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -605,7 +605,7 @@ public class VpnManagerService extends IVpnManager.Stub { return null; } else { final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo(); - return (info == null || info.ownerUid != uid) ? null : vpn; + return (info == null || info.getOwnerUid() != uid) ? null : vpn; } } diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index a37115d1f5c7..2e3827833856 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -96,6 +96,7 @@ public class Watchdog extends Thread { "/system/bin/audioserver", "/system/bin/cameraserver", "/system/bin/drmserver", + "/system/bin/keystore2", "/system/bin/mediadrmserver", "/system/bin/mediaserver", "/system/bin/netd", diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java index f41c36404c50..1ecb9eb81709 100644 --- a/services/core/java/com/android/server/am/LmkdConnection.java +++ b/services/core/java/com/android/server/am/LmkdConnection.java @@ -31,6 +31,8 @@ import com.android.internal.annotations.GuardedBy; import libcore.io.IoUtils; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; @@ -43,8 +45,12 @@ import java.nio.ByteBuffer; public class LmkdConnection { private static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdConnection" : TAG_AM; - // lmkd reply max size in bytes - private static final int LMKD_REPLY_MAX_SIZE = 12; + /** + * Max LMKD reply packet length in bytes + * Used to hold the data for the statsd atoms logging + * Must be in sync with statslog.h + */ + private static final int LMKD_REPLY_MAX_SIZE = 214; // connection listener interface interface LmkdConnectionListener { @@ -70,7 +76,7 @@ public class LmkdConnection { * @param receivedLen Size of the data received * @return True if the message has been handled correctly, false otherwise. */ - boolean handleUnsolicitedMessage(ByteBuffer dataReceived, int receivedLen); + boolean handleUnsolicitedMessage(DataInputStream inputData, int receivedLen); } private final MessageQueue mMsgQueue; @@ -95,6 +101,10 @@ public class LmkdConnection { private final ByteBuffer mInputBuf = ByteBuffer.allocate(LMKD_REPLY_MAX_SIZE); + // Input stream to parse the incoming data + private final DataInputStream mInputData = new DataInputStream( + new ByteArrayInputStream(mInputBuf.array())); + // object to protect mReplyBuf and to wait/notify when reply is received private final Object mReplyBufLock = new Object(); @@ -186,26 +196,32 @@ public class LmkdConnection { private void processIncomingData() { int len = read(mInputBuf); if (len > 0) { - synchronized (mReplyBufLock) { - if (mReplyBuf != null) { - if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) { - // copy into reply buffer - mReplyBuf.put(mInputBuf.array(), 0, len); - mReplyBuf.rewind(); - // wakeup the waiting thread - mReplyBufLock.notifyAll(); - } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) { - // received unexpected packet - // treat this as an error - mReplyBuf = null; - mReplyBufLock.notifyAll(); - Slog.e(TAG, "Received an unexpected packet from lmkd"); + try { + // reset InputStream to point into mInputBuf.array() begin + mInputData.reset(); + synchronized (mReplyBufLock) { + if (mReplyBuf != null) { + if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) { + // copy into reply buffer + mReplyBuf.put(mInputBuf.array(), 0, len); + mReplyBuf.rewind(); + // wakeup the waiting thread + mReplyBufLock.notifyAll(); + } else if (!mListener.handleUnsolicitedMessage(mInputData, len)) { + // received unexpected packet + // treat this as an error + mReplyBuf = null; + mReplyBufLock.notifyAll(); + Slog.e(TAG, "Received an unexpected packet from lmkd"); + } + } else if (!mListener.handleUnsolicitedMessage(mInputData, len)) { + // received asynchronous communication from lmkd + // but we don't recognize it. + Slog.w(TAG, "Received an unexpected packet from lmkd"); } - } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) { - // received asynchronous communication from lmkd - // but we don't recognize it. - Slog.w(TAG, "Received an unexpected packet from lmkd"); } + } catch (IOException e) { + Slog.e(TAG, "Failed to parse lmkd data buffer. Size = " + len); } } } diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java new file mode 100644 index 000000000000..c702d780bd6b --- /dev/null +++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; + +import android.util.Slog; + +import com.android.internal.util.FrameworkStatsLog; + +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Activity manager communication with lmkd data handling and statsd atom logging + */ +public final class LmkdStatsReporter { + + static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdStatsReporter" : TAG_AM; + + public static final int KILL_OCCURRED_MSG_SIZE = 80; + public static final int STATE_CHANGED_MSG_SIZE = 8; + + private static final int PRESSURE_AFTER_KILL = 0; + private static final int NOT_RESPONDING = 1; + private static final int LOW_SWAP_AND_THRASHING = 2; + private static final int LOW_MEM_AND_SWAP = 3; + private static final int LOW_MEM_AND_THRASHING = 4; + private static final int DIRECT_RECL_AND_THRASHING = 5; + private static final int LOW_MEM_AND_SWAP_UTIL = 6; + + /** + * Processes the LMK_KILL_OCCURRED packet data + * Logs the event when LMKD kills a process to reduce memory pressure. + * Code: LMK_KILL_OCCURRED = 51 + */ + public static void logKillOccurred(DataInputStream inputData) { + try { + final long pgFault = inputData.readLong(); + final long pgMajFault = inputData.readLong(); + final long rssInBytes = inputData.readLong(); + final long cacheInBytes = inputData.readLong(); + final long swapInBytes = inputData.readLong(); + final long processStartTimeNS = inputData.readLong(); + final int uid = inputData.readInt(); + final int oomScore = inputData.readInt(); + final int minOomScore = inputData.readInt(); + final int freeMemKb = inputData.readInt(); + final int freeSwapKb = inputData.readInt(); + final int killReason = inputData.readInt(); + final String procName = inputData.readUTF(); + + FrameworkStatsLog.write(FrameworkStatsLog.LMK_KILL_OCCURRED, uid, procName, oomScore, + pgFault, pgMajFault, rssInBytes, cacheInBytes, swapInBytes, processStartTimeNS, + minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason)); + } catch (IOException e) { + Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED"); + return; + } + } + + /** + * Processes the LMK_STATE_CHANGED packet + * Logs the change in LMKD state which is used as start/stop boundaries for logging + * LMK_KILL_OCCURRED event. + * Code: LMK_STATE_CHANGED = 54 + */ + public static void logStateChanged(int state) { + FrameworkStatsLog.write(FrameworkStatsLog.LMK_STATE_CHANGED, state); + } + + private static int mapKillReason(int reason) { + switch (reason) { + case PRESSURE_AFTER_KILL: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__PRESSURE_AFTER_KILL; + case NOT_RESPONDING: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__NOT_RESPONDING; + case LOW_SWAP_AND_THRASHING: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_SWAP_AND_THRASHING; + case LOW_MEM_AND_SWAP: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP; + case LOW_MEM_AND_THRASHING: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_THRASHING; + case DIRECT_RECL_AND_THRASHING: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__DIRECT_RECL_AND_THRASHING; + case LOW_MEM_AND_SWAP_UTIL: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP_UTIL; + default: + return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__UNKNOWN; + } + } +} diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 444418cd3d6e..e9b014621e70 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -125,6 +125,7 @@ import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; +import java.io.DataInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; @@ -316,18 +317,25 @@ public final class ProcessList { // LMK_GETKILLCNT // LMK_SUBSCRIBE // LMK_PROCKILL + // LMK_UPDATE_PROPS + // LMK_KILL_OCCURRED + // LMK_STATE_CHANGED static final byte LMK_TARGET = 0; static final byte LMK_PROCPRIO = 1; static final byte LMK_PROCREMOVE = 2; static final byte LMK_PROCPURGE = 3; static final byte LMK_GETKILLCNT = 4; static final byte LMK_SUBSCRIBE = 5; - static final byte LMK_PROCKILL = 6; // Note: this is an unsolicated command + static final byte LMK_PROCKILL = 6; // Note: this is an unsolicited command + static final byte LMK_UPDATE_PROPS = 7; + static final byte LMK_KILL_OCCURRED = 8; // Msg to subscribed clients on kill occurred event + static final byte LMK_STATE_CHANGED = 9; // Msg to subscribed clients on state changed // Low Memory Killer Daemon command codes. // These must be kept in sync with async_event_type definitions in lmkd.h // static final int LMK_ASYNC_EVENT_KILL = 0; + static final int LMK_ASYNC_EVENT_STAT = 1; // lmkd reconnect delay in msecs private static final long LMKD_RECONNECT_DELAY_MS = 1000; @@ -776,22 +784,44 @@ public final class ProcessList { } @Override - public boolean handleUnsolicitedMessage(ByteBuffer dataReceived, + public boolean handleUnsolicitedMessage(DataInputStream inputData, int receivedLen) { if (receivedLen < 4) { return false; } - switch (dataReceived.getInt(0)) { - case LMK_PROCKILL: - if (receivedLen != 12) { + + try { + switch (inputData.readInt()) { + case LMK_PROCKILL: + if (receivedLen != 12) { + return false; + } + final int pid = inputData.readInt(); + final int uid = inputData.readInt(); + mAppExitInfoTracker.scheduleNoteLmkdProcKilled(pid, uid); + return true; + case LMK_KILL_OCCURRED: + if (receivedLen + < LmkdStatsReporter.KILL_OCCURRED_MSG_SIZE) { + return false; + } + LmkdStatsReporter.logKillOccurred(inputData); + return true; + case LMK_STATE_CHANGED: + if (receivedLen + != LmkdStatsReporter.STATE_CHANGED_MSG_SIZE) { + return false; + } + final int state = inputData.readInt(); + LmkdStatsReporter.logStateChanged(state); + return true; + default: return false; - } - mAppExitInfoTracker.scheduleNoteLmkdProcKilled( - dataReceived.getInt(4), dataReceived.getInt(8)); - return true; - default: - return false; + } + } catch (IOException e) { + Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED"); } + return false; } } ); @@ -1433,6 +1463,12 @@ public final class ProcessList { buf.putInt(LMK_SUBSCRIBE); buf.putInt(LMK_ASYNC_EVENT_KILL); ostream.write(buf.array(), 0, buf.position()); + + // Subscribe for stats event notifications + buf = ByteBuffer.allocate(4 * 2); + buf.putInt(LMK_SUBSCRIBE); + buf.putInt(LMK_ASYNC_EVENT_STAT); + ostream.write(buf.array(), 0, buf.position()); } catch (IOException ex) { return false; } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 22a6044fbb8a..d0a307932db0 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -5860,6 +5860,10 @@ public class AudioService extends IAudioService.Stub if (index == -1) { continue; } + if (mPublicStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED + && mCameraSoundForced) { + index = mIndexMax; + } if (DEBUG_VOL) { Log.v(TAG, "readSettings: found stored index " + getValidIndex(index) + " for group " + mAudioVolumeGroup.name() + ", device: " + name); diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 131267924179..8fd8b5c2cded 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -289,7 +289,7 @@ public class AuthService extends SystemService { } @Override - public long[] getAuthenticatorIds() throws RemoteException { + public long[] getAuthenticatorIds(int userId) throws RemoteException { // In this method, we're not checking whether the caller is permitted to use face // API because current authenticator ID is leaked (in a more contrived way) via Android // Keystore (android.security.keystore package): the user of that API can create a key @@ -307,9 +307,13 @@ public class AuthService extends SystemService { // method from inside app processes. final int callingUserId = UserHandle.getCallingUserId(); + if (userId != callingUserId) { + getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL, + "Must have " + USE_BIOMETRIC_INTERNAL + " permission."); + } final long identity = Binder.clearCallingIdentity(); try { - return mBiometricService.getAuthenticatorIds(callingUserId); + return mBiometricService.getAuthenticatorIds(userId); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/biometrics/OWNERS b/services/core/java/com/android/server/biometrics/OWNERS index 8765c9a64b77..4eac97286880 100644 --- a/services/core/java/com/android/server/biometrics/OWNERS +++ b/services/core/java/com/android/server/biometrics/OWNERS @@ -5,3 +5,4 @@ jaggies@google.com curtislb@google.com ilyamaty@google.com joshmccloskey@google.com +jbolinger@google.com diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 55e269630093..924756889408 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -33,6 +33,7 @@ import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; import com.android.internal.compat.IOverrideValidator; import com.android.internal.compat.OverrideAllowedState; import com.android.server.compat.config.Change; @@ -370,6 +371,27 @@ final class CompatConfig { } } + /** + * Removes overrides whose change ID is specified in {@code overridesToRemove} that were + * previously added via {@link #addOverride(long, String, boolean)} or + * {@link #addOverrides(CompatibilityOverrideConfig, String)} for a certain package. + * + * <p>This restores the default behaviour for the given change IDs and app. + * + * @param overridesToRemove list of change IDs for which to restore the default behaviour. + * @param packageName the package for which the overrides should be purged + */ + void removePackageOverrides(CompatibilityOverridesToRemoveConfig overridesToRemove, + String packageName) { + synchronized (mChanges) { + for (Long changeId : overridesToRemove.changeIds) { + removeOverrideUnsafe(changeId, packageName); + } + saveOverrides(); + invalidateCache(); + } + } + private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName, int targetSdkVersion) { LongArray allowed = new LongArray(); diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 20469a21db0c..2591f38b2bb3 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -46,6 +46,7 @@ import com.android.internal.compat.ChangeReporter; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; import com.android.internal.compat.IOverrideValidator; import com.android.internal.compat.IPlatformCompat; import com.android.internal.util.DumpUtils; @@ -54,6 +55,7 @@ import com.android.server.LocalServices; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -187,7 +189,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { String packageName) { // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods. checkCompatChangeOverrideOverridablePermission(); - checkAllCompatOverridesAreOverridable(overrides); + checkAllCompatOverridesAreOverridable(overrides.overrides.keySet()); mCompatConfig.addOverrides(overrides, packageName); } @@ -251,6 +253,16 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override + public void removeOverridesOnReleaseBuilds( + CompatibilityOverridesToRemoveConfig overridesToRemove, + String packageName) { + // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods. + checkCompatChangeOverrideOverridablePermission(); + checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds); + mCompatConfig.removePackageOverrides(overridesToRemove, packageName); + } + + @Override public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) { checkCompatChangeReadAndLogPermission(); return mCompatConfig.getAppConfig(appInfo); @@ -396,8 +408,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { } } - private void checkAllCompatOverridesAreOverridable(CompatibilityOverrideConfig overrides) { - for (Long changeId : overrides.overrides.keySet()) { + private void checkAllCompatOverridesAreOverridable(Collection<Long> changeIds) { + for (Long changeId : changeIds) { if (!mCompatConfig.isOverridable(changeId)) { throw new SecurityException("Only change ids marked as Overridable can be " + "overridden."); diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 4ecc7594a79c..091e6c4adf4d 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -27,6 +27,7 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; import static android.net.NetworkTemplate.OEM_MANAGED_ALL; +import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT; import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -227,7 +228,8 @@ public class MultipathPolicyTracker { mNetworkTemplate = new NetworkTemplate( NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId }, null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, - NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); + NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); mUsageCallback = new UsageCallback() { @Override public void onThresholdReached(int networkType, String subscriberId) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index afaae8a5b776..0677bd554341 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -806,7 +806,6 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { Arrays.stream(device.getEncodings()).mapToObj( AudioFormat::toLogFriendlyEncoding ).collect(Collectors.joining(", "))); - // TODO(b/80297701) use the actual device type that system audio mode is connected to. if (device.getType() == AudioDeviceInfo.TYPE_HDMI_ARC) { return device; } @@ -1225,7 +1224,6 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { if (isSystemAudioActivated() && port < 0) { // If system audio mode is on and the new active source is not under the current device, // Will switch to ARC input. - // TODO(b/115637145): handle system aduio without ARC routeToInputFromPortId(Constants.CEC_SWITCH_ARC); } else if (mIsSwitchDevice && port >= 0) { // If current device is a switch and the new active source is under it, @@ -1326,7 +1324,6 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { // Handle the system audio(ARC) part of the logic on receiving routing change or information. private void handleRoutingChangeAndInformationForSystemAudio() { - // TODO(b/115637145): handle system aduio without ARC routeToInputFromPortId(Constants.CEC_SWITCH_ARC); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java index 3f949bab8a2e..ec41a2fde1ad 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java @@ -475,7 +475,6 @@ public class HdmiCecMessageBuilder { * @return newly created {@link HdmiCecMessage} */ static HdmiCecMessage buildReportShortAudioDescriptor(int src, int des, byte[] sadBytes) { - // TODO(b/80297701) validate. return buildCommand(src, des, Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, sadBytes); } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java index 740407c42178..e2330849d66d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java @@ -86,6 +86,8 @@ final class HdmiControlShellCommand extends ShellCommand { pw.println(" Send a Vendor Command to the given target device"); pw.println(" setsystemaudiomode, setsam [on|off]"); pw.println(" Sets the System Audio Mode feature on or off on TV devices"); + pw.println(" setarc [on|off]"); + pw.println(" Sets the ARC feature on or off on TV devices"); } private int handleShellCommand(String cmd) throws RemoteException { @@ -100,6 +102,8 @@ final class HdmiControlShellCommand extends ShellCommand { case "setsystemaudiomode": case "setsam": return setSystemAudioMode(pw); + case "setarc": + return setArcMode(pw); } getErrPrintWriter().println("Unhandled command: " + cmd); @@ -188,6 +192,27 @@ final class HdmiControlShellCommand extends ShellCommand { return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1; } + private int setArcMode(PrintWriter pw) throws RemoteException { + if (1 > getRemainingArgsCount()) { + throw new IllegalArgumentException( + "Please indicate if ARC mode should be turned \"on\" or \"off\"."); + } + + String arg = getNextArg(); + if (arg.equals("on")) { + pw.println("Setting ARC mode on"); + mBinderService.setArcMode(true); + } else if (arg.equals("off")) { + pw.println("Setting ARC mode off"); + mBinderService.setArcMode(false); + } else { + throw new IllegalArgumentException( + "Please indicate if ARC mode should be turned \"on\" or \"off\"."); + } + + return 0; + } + private boolean receiveCallback(String command) { try { if (!mLatch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) { diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java index 0907e5d03c78..0864a44cf5ee 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java @@ -142,8 +142,4 @@ public class SystemAudioInitiationActionFromAvr extends HdmiCecFeatureAction { } }); } - - private void switchToRelevantInputForDeviceAt(int physicalAddress) { - // TODO(shubang): implement this method - } } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 117c85bfdf77..07ac14f049c2 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -29,6 +29,8 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; +import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_DECRYPT; +import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE; @@ -99,6 +101,7 @@ import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; import android.security.keystore.recovery.RecoveryCertPath; import android.security.keystore.recovery.WrappedApplicationKey; +import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import android.security.keystore2.AndroidKeyStoreProvider; import android.service.gatekeeper.GateKeeperResponse; import android.service.gatekeeper.IGateKeeperService; @@ -153,6 +156,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -225,6 +229,7 @@ public class LockSettingsService extends ILockSettings.Stub { private final SyntheticPasswordManager mSpManager; private final KeyStore mKeyStore; + private final java.security.KeyStore mJavaKeyStore; private final RecoverableKeyStoreManager mRecoverableKeyStoreManager; private ManagedProfilePasswordCache mManagedProfilePasswordCache; @@ -543,16 +548,22 @@ public class LockSettingsService extends ILockSettings.Stub { return Settings.Secure.getIntForUser(contentResolver, keyName, defaultValue, userId); } - public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache() { + public java.security.KeyStore getJavaKeyStore() { try { java.security.KeyStore ks = java.security.KeyStore.getInstance( SyntheticPasswordCrypto.androidKeystoreProviderName()); - ks.load(null); - return new ManagedProfilePasswordCache(ks, getUserManager()); + ks.load(new AndroidKeyStoreLoadStoreParameter( + SyntheticPasswordCrypto.keyNamespace())); + return ks; } catch (Exception e) { throw new IllegalStateException("Cannot load keystore", e); } } + + public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache( + java.security.KeyStore ks) { + return new ManagedProfilePasswordCache(ks, getUserManager()); + } } public LockSettingsService(Context context) { @@ -564,6 +575,7 @@ public class LockSettingsService extends ILockSettings.Stub { mInjector = injector; mContext = injector.getContext(); mKeyStore = injector.getKeyStore(); + mJavaKeyStore = injector.getJavaKeyStore(); mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(); mHandler = injector.getHandler(injector.getServiceThread()); mStrongAuth = injector.getStrongAuth(); @@ -586,7 +598,7 @@ public class LockSettingsService extends ILockSettings.Stub { mStrongAuthTracker.register(mStrongAuth); mSpManager = injector.getSyntheticPasswordManager(mStorage); - mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(); + mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(mJavaKeyStore); mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(), mStorage); @@ -959,6 +971,21 @@ public class LockSettingsService extends ILockSettings.Stub { setString("migrated_wear_lockscreen_disabled", "true", 0); Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices"); } + + if (getString("migrated_keystore_namespace", null, 0) == null) { + boolean success = true; + synchronized (mSpManager) { + success &= mSpManager.migrateKeyNamespace(); + } + success &= migrateProfileLockKeys(); + if (success) { + setString("migrated_keystore_namespace", "true", 0); + Slog.i(TAG, "Migrated keys to LSS namespace"); + } else { + Slog.w(TAG, "Failed to migrate keys to LSS namespace"); + } + } + } private void migrateOldDataAfterSystemReady() { @@ -999,6 +1026,22 @@ public class LockSettingsService extends ILockSettings.Stub { } } + private boolean migrateProfileLockKeys() { + boolean success = true; + final List<UserInfo> users = mUserManager.getUsers(); + final int userCount = users.size(); + for (int i = 0; i < userCount; i++) { + UserInfo user = users.get(i); + if (user.isManagedProfile() && !getSeparateProfileChallengeEnabledInternal(user.id)) { + success &= SyntheticPasswordCrypto.migrateLockSettingsKey( + PROFILE_KEY_NAME_ENCRYPT + user.id); + success &= SyntheticPasswordCrypto.migrateLockSettingsKey( + PROFILE_KEY_NAME_DECRYPT + user.id); + } + } + return success; + } + /** * Returns the lowest password quality that still presents the same UI for entering it. * @@ -1266,7 +1309,7 @@ public class LockSettingsService extends ILockSettings.Stub { private void unlockKeystore(byte[] password, int userHandle) { if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle); - Authorization.onLockScreenEvent(false, userHandle, password); + Authorization.onLockScreenEvent(false, userHandle, password, null); } @VisibleForTesting /** Note: this method is overridden in unit tests */ @@ -1284,11 +1327,8 @@ public class LockSettingsService extends ILockSettings.Stub { byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE, storedData.length); byte[] decryptionResult; - java.security.KeyStore keyStore = java.security.KeyStore.getInstance( - SyntheticPasswordCrypto.androidKeystoreProviderName()); - keyStore.load(null); - SecretKey decryptionKey = (SecretKey) keyStore.getKey( - LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null); + SecretKey decryptionKey = (SecretKey) mJavaKeyStore.getKey( + PROFILE_KEY_NAME_DECRYPT + userId, null); Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); @@ -1744,30 +1784,26 @@ public class LockSettingsService extends ILockSettings.Stub { KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); keyGenerator.init(new SecureRandom()); SecretKey secretKey = keyGenerator.generateKey(); - java.security.KeyStore keyStore = java.security.KeyStore.getInstance( - SyntheticPasswordCrypto.androidKeystoreProviderName()); - keyStore.load(null); try { - keyStore.setEntry( - LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, + mJavaKeyStore.setEntry( + PROFILE_KEY_NAME_ENCRYPT + userId, new java.security.KeyStore.SecretKeyEntry(secretKey), new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .build()); - keyStore.setEntry( - LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, + mJavaKeyStore.setEntry( + PROFILE_KEY_NAME_DECRYPT + userId, new java.security.KeyStore.SecretKeyEntry(secretKey), new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setUserAuthenticationRequired(true) .setUserAuthenticationValidityDurationSeconds(30) - .setCriticalToDeviceEncryption(true) .build()); // Key imported, obtain a reference to it. - SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey( - LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null); + SecretKey keyStoreEncryptionKey = (SecretKey) mJavaKeyStore.getKey( + PROFILE_KEY_NAME_ENCRYPT + userId, null); Cipher cipher = Cipher.getInstance( KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); @@ -1776,10 +1812,10 @@ public class LockSettingsService extends ILockSettings.Stub { iv = cipher.getIV(); } finally { // The original key can now be discarded. - keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId); + mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + userId); } - } catch (CertificateException | UnrecoverableKeyException - | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException + } catch (UnrecoverableKeyException + | BadPaddingException | IllegalBlockSizeException | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { throw new IllegalStateException("Failed to encrypt key", e); } @@ -2300,13 +2336,9 @@ public class LockSettingsService extends ILockSettings.Stub { private void removeKeystoreProfileKey(int targetUserId) { Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId); try { - java.security.KeyStore keyStore = java.security.KeyStore.getInstance( - SyntheticPasswordCrypto.androidKeystoreProviderName()); - keyStore.load(null); - keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId); - keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId); - } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException - | IOException e) { + mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + targetUserId); + mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_DECRYPT + targetUserId); + } catch (KeyStoreException e) { // We have tried our best to remove all keys Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e); } @@ -3257,6 +3289,12 @@ public class LockSettingsService extends ILockSettings.Stub { pw.println(); pw.decreaseIndent(); + pw.println("Keys in namespace:"); + pw.increaseIndent(); + dumpKeystoreKeys(pw); + pw.println(); + pw.decreaseIndent(); + pw.println("Storage:"); pw.increaseIndent(); mStorage.dump(pw); @@ -3276,6 +3314,18 @@ public class LockSettingsService extends ILockSettings.Stub { pw.decreaseIndent(); } + private void dumpKeystoreKeys(IndentingPrintWriter pw) { + try { + final Enumeration<String> aliases = mJavaKeyStore.aliases(); + while (aliases.hasMoreElements()) { + pw.println(aliases.nextElement()); + } + } catch (KeyStoreException e) { + pw.println("Unable to get keys: " + e.toString()); + Slog.d(TAG, "Dump error", e); + } + } + /** * Cryptographically disable escrow token support for the current user, if the user is not * managed (either user has a profile owner, or if device is managed). Do not disable diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java index fa477c8fd35a..672c3f739413 100644 --- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java +++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java @@ -23,7 +23,6 @@ import android.os.UserManager; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.security.keystore.UserNotAuthenticatedException; -import android.security.keystore2.AndroidKeyStoreSpi; import android.util.Slog; import android.util.SparseArray; @@ -95,11 +94,12 @@ public class ManagedProfilePasswordCache { SecretKey key; try { generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, - AndroidKeyStoreSpi.NAME); + mKeyStore.getProvider()); generator.init(new KeyGenParameterSpec.Builder( keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setKeySize(KEY_LENGTH) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setNamespace(SyntheticPasswordCrypto.keyNamespace()) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) // Generate auth-bound key to user 0 (since we the caller is user 0) .setUserAuthenticationRequired(true) diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 90694d0a5f64..3f2b8fffcc54 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -31,6 +31,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Handler; import android.os.SystemClock; @@ -224,6 +225,12 @@ class RebootEscrowManager { } public boolean serverBasedResumeOnReboot() { + // Always use the server based RoR if the HAL isn't installed on device. + if (!mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_REBOOT_ESCROW)) { + return true; + } + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, "server_based_ror_enabled", false); } @@ -374,6 +381,7 @@ class RebootEscrowManager { try { escrowKey = getAndClearRebootEscrowKey(kk); } catch (IOException e) { + Slog.i(TAG, "Failed to load escrow key, scheduling retry.", e); scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users, rebootEscrowUsers); return; diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java index 35e6489debcf..3386408f32cc 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java @@ -16,8 +16,12 @@ package com.android.server.locksettings; +import android.security.AndroidKeyStoreMaintenance; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; +import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; import android.util.Slog; import java.io.ByteArrayOutputStream; @@ -125,9 +129,7 @@ public class SyntheticPasswordCrypto { public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) { try { - KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); - keyStore.load(null); - + KeyStore keyStore = getKeyStore(); SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null); if (decryptionKey == null) { throw new IllegalStateException("SP key is missing: " + keyAlias); @@ -144,10 +146,20 @@ public class SyntheticPasswordCrypto { return "AndroidKeyStore"; } + static int keyNamespace() { + return KeyProperties.NAMESPACE_LOCKSETTINGS; + } + + private static KeyStore getKeyStore() + throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { + KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); + keyStore.load(new AndroidKeyStoreLoadStoreParameter(keyNamespace())); + return keyStore; + } + public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) { try { - KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); - keyStore.load(null); + final KeyStore keyStore = getKeyStore(); SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null); if (decryptionKey == null) { @@ -170,8 +182,7 @@ public class SyntheticPasswordCrypto { KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); keyGenerator.init(AES_KEY_LENGTH * 8, new SecureRandom()); SecretKey secretKey = keyGenerator.generateKey(); - KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); - keyStore.load(null); + final KeyStore keyStore = getKeyStore(); KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) @@ -200,8 +211,7 @@ public class SyntheticPasswordCrypto { public static void destroyBlobKey(String keyAlias) { KeyStore keyStore; try { - keyStore = KeyStore.getInstance(androidKeystoreProviderName()); - keyStore.load(null); + keyStore = getKeyStore(); keyStore.deleteEntry(keyAlias); Slog.i(TAG, "SP key deleted: " + keyAlias); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException @@ -229,4 +239,32 @@ public class SyntheticPasswordCrypto { throw new IllegalStateException("NoSuchAlgorithmException for SHA-512", e); } } + + static boolean migrateLockSettingsKey(String alias) { + final KeyDescriptor legacyKey = new KeyDescriptor(); + legacyKey.domain = Domain.APP; + legacyKey.nspace = KeyProperties.NAMESPACE_APPLICATION; + legacyKey.alias = alias; + + final KeyDescriptor newKey = new KeyDescriptor(); + newKey.domain = Domain.SELINUX; + newKey.nspace = SyntheticPasswordCrypto.keyNamespace(); + newKey.alias = alias; + Slog.i(TAG, "Migrating key " + alias); + int err = AndroidKeyStoreMaintenance.migrateKeyNamespace(legacyKey, newKey); + if (err == 0) { + return true; + } else if (err == AndroidKeyStoreMaintenance.KEY_NOT_FOUND) { + Slog.i(TAG, "Key does not exist"); + // Treat this as a success so we don't migrate again. + return true; + } else if (err == AndroidKeyStoreMaintenance.INVALID_ARGUMENT) { + Slog.i(TAG, "Key already exists"); + // Treat this as a success so we don't migrate again. + return true; + } else { + Slog.e(TAG, String.format("Failed to migrate key: %d", err)); + return false; + } + } } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 6b5295f70598..0c182a01585d 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -519,7 +519,7 @@ public class SyntheticPasswordManager { public void removeUser(int userId) { for (long handle : mStorage.listSyntheticPasswordHandlesForUser(SP_BLOB_NAME, userId)) { destroyWeaverSlot(handle, userId); - destroySPBlobKey(getHandleName(handle)); + destroySPBlobKey(getKeyName(handle)); } } @@ -955,7 +955,7 @@ public class SyntheticPasswordManager { } else { secret = authToken.getSyntheticPassword(); } - byte[] content = createSPBlob(getHandleName(handle), secret, applicationId, sid); + byte[] content = createSPBlob(getKeyName(handle), secret, applicationId, sid); byte[] blob = new byte[content.length + 1 + 1]; /* * We can upgrade from v1 to v2 because that's just a change in the way that @@ -1137,10 +1137,10 @@ public class SyntheticPasswordManager { } final byte[] secret; if (version == SYNTHETIC_PASSWORD_VERSION_V1) { - secret = SyntheticPasswordCrypto.decryptBlobV1(getHandleName(handle), + secret = SyntheticPasswordCrypto.decryptBlobV1(getKeyName(handle), Arrays.copyOfRange(blob, 2, blob.length), applicationId); } else { - secret = decryptSPBlob(getHandleName(handle), + secret = decryptSPBlob(getKeyName(handle), Arrays.copyOfRange(blob, 2, blob.length), applicationId); } if (secret == null) { @@ -1235,7 +1235,7 @@ public class SyntheticPasswordManager { private void destroySyntheticPassword(long handle, int userId) { destroyState(SP_BLOB_NAME, handle, userId); - destroySPBlobKey(getHandleName(handle)); + destroySPBlobKey(getKeyName(handle)); if (hasState(WEAVER_SLOT_NAME, handle, userId)) { destroyWeaverSlot(handle, userId); } @@ -1351,7 +1351,7 @@ public class SyntheticPasswordManager { } } - private String getHandleName(long handle) { + private String getKeyName(long handle) { return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle); } @@ -1412,4 +1412,19 @@ public class SyntheticPasswordManager { } return hexBytes; } + + /** + * Migrate all existing SP keystore keys from uid 1000 app domain to LSS selinux domain + */ + public boolean migrateKeyNamespace() { + boolean success = true; + final Map<Integer, List<Long>> allHandles = + mStorage.listSyntheticPasswordHandlesForAllUsers(SP_BLOB_NAME); + for (List<Long> userHandles : allHandles.values()) { + for (long handle : userHandles) { + success &= SyntheticPasswordCrypto.migrateLockSettingsKey(getKeyName(handle)); + } + } + return success; + } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 1f44d250c216..d0da91207a47 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -1921,7 +1921,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Collect all ifaces from a {@link NetworkStateSnapshot} into the given set. */ private static void collectIfaces(ArraySet<String> ifaces, NetworkStateSnapshot snapshot) { - ifaces.addAll(snapshot.linkProperties.getAllInterfaceNames()); + ifaces.addAll(snapshot.getLinkProperties().getAllInterfaceNames()); } /** @@ -1995,14 +1995,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (LOGV) Slog.v(TAG, "updateNetworkRulesNL()"); Trace.traceBegin(TRACE_TAG_NETWORK, "updateNetworkRulesNL"); - final List<NetworkStateSnapshot> snapshots = mConnManager.getAllNetworkStateSnapshot(); + final List<NetworkStateSnapshot> snapshots = mConnManager.getAllNetworkStateSnapshots(); // First, generate identities of all connected networks so we can // quickly compare them against all defined policies below. mNetIdToSubId.clear(); final ArrayMap<NetworkStateSnapshot, NetworkIdentity> identified = new ArrayMap<>(); for (final NetworkStateSnapshot snapshot : snapshots) { - mNetIdToSubId.put(snapshot.network.getNetId(), parseSubId(snapshot)); + mNetIdToSubId.put(snapshot.getNetwork().getNetId(), parseSubId(snapshot)); // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype // in the object created here is never used and its value doesn't matter, so use @@ -2090,7 +2090,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // One final pass to catch any metered ifaces that don't have explicitly // defined policies; typically Wi-Fi networks. for (final NetworkStateSnapshot snapshot : snapshots) { - if (!snapshot.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) { + if (!snapshot.getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)) { matchingIfaces.clear(); collectIfaces(matchingIfaces, snapshot); for (int j = matchingIfaces.size() - 1; j >= 0; j--) { @@ -2126,14 +2126,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mSubscriptionOpportunisticQuota.clear(); for (final NetworkStateSnapshot snapshot : snapshots) { if (!quotaEnabled) continue; - if (snapshot.network == null) continue; - final int subId = getSubIdLocked(snapshot.network); + if (snapshot.getNetwork() == null) continue; + final int subId = getSubIdLocked(snapshot.getNetwork()); final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId); if (plan == null) continue; final long quotaBytes; final long limitBytes = plan.getDataLimitBytes(); - if (!snapshot.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) { + if (!snapshot.getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_ROAMING)) { // Clamp to 0 when roaming quotaBytes = 0; } else if (limitBytes == SubscriptionPlan.BYTES_UNKNOWN) { @@ -2151,7 +2151,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { .truncatedTo(ChronoUnit.DAYS) .toInstant().toEpochMilli(); final long totalBytes = getTotalBytes( - NetworkTemplate.buildTemplateMobileAll(snapshot.subscriberId), + NetworkTemplate.buildTemplateMobileAll(snapshot.getSubscriberId()), start, startOfDay); final long remainingBytes = limitBytes - totalBytes; // Number of remaining days including current day @@ -5770,8 +5770,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private int parseSubId(@NonNull NetworkStateSnapshot snapshot) { int subId = INVALID_SUBSCRIPTION_ID; - if (snapshot.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { - NetworkSpecifier spec = snapshot.networkCapabilities.getNetworkSpecifier(); + if (snapshot.getNetworkCapabilities().hasTransport(TRANSPORT_CELLULAR)) { + NetworkSpecifier spec = snapshot.getNetworkCapabilities().getNetworkSpecifier(); if (spec instanceof TelephonyNetworkSpecifier) { subId = ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); } diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index d042b882fee1..431b00914f02 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -382,8 +382,8 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (UnderlyingNetworkInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.iface, - info.underlyingIfaces.toArray(new String[0])); + delta.migrateTun(info.getOwnerUid(), info.getInterface(), + info.getUnderlyingInterfaces()); // Filter out debug entries as that may lead to over counting. delta.filterDebugEntries(); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 19f5e3cd5dfa..4ee867b7d051 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -24,7 +24,6 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -97,12 +96,12 @@ import android.net.INetworkStatsSession; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; +import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; -import android.net.NetworkSpecifier; import android.net.NetworkTemplate; import android.net.TelephonyNetworkSpecifier; import android.net.TrafficStats; @@ -182,7 +181,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 1; // Perform polling, persist network, and register the global alert again. private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; - private static final int MSG_UPDATE_IFACES = 3; + private static final int MSG_NOTIFY_NETWORK_STATUS = 3; // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent // deadlock. private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4; @@ -380,11 +379,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(FLAG_PERSIST_ALL); break; } - case MSG_UPDATE_IFACES: { + case MSG_NOTIFY_NETWORK_STATUS: { // If no cached states, ignore. if (mLastNetworkStateSnapshots == null) break; // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing. - updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); + handleNotifyNetworkStatus( + mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); break; } case MSG_PERFORM_POLL_REGISTER_ALERT: { @@ -475,7 +475,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull Looper looper, @NonNull Executor executor, @NonNull NetworkStatsService service) { // TODO: Update RatType passively in NSS, instead of querying into the monitor - // when forceUpdateIface. + // when notifyNetworkStatus. return new NetworkStatsSubscriptionsMonitor(context, looper, executor, (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); } @@ -972,16 +972,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public void forceUpdateIfaces( - Network[] defaultNetworks, - NetworkStateSnapshot[] networkStates, - String activeIface, - UnderlyingNetworkInfo[] underlyingNetworkInfos) { + /** + * Notify {@code NetworkStatsService} about network status changed. + */ + public void notifyNetworkStatus( + @NonNull Network[] defaultNetworks, + @NonNull NetworkStateSnapshot[] networkStates, + @Nullable String activeIface, + @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) { checkNetworkStackPermission(mContext); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks, networkStates, activeIface); + handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1245,12 +1248,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting public void handleOnCollapsedRatTypeChanged() { // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_UPDATE_IFACES); + mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS); mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); + mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS), mSettings.getPollDelay()); } - private void updateIfaces( + private void handleNotifyNetworkStatus( Network[] defaultNetworks, NetworkStateSnapshot[] snapshots, String activeIface) { @@ -1258,7 +1261,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mWakeLock.acquire(); try { mActiveIface = activeIface; - updateIfacesLocked(defaultNetworks, snapshots); + handleNotifyNetworkStatusLocked(defaultNetworks, snapshots); } finally { mWakeLock.release(); } @@ -1271,10 +1274,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(@NonNull Network[] defaultNetworks, + private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks, @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; - if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); + if (LOGV) Slog.v(TAG, "handleNotifyNetworkStatusLocked()"); // take one last stats snapshot before updating iface mapping. this // isn't perfect, since the kernel may already be counting traffic from @@ -1296,9 +1299,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final ArraySet<String> mobileIfaces = new ArraySet<>(); for (NetworkStateSnapshot snapshot : snapshots) { final int displayTransport = - getDisplayTransport(snapshot.networkCapabilities.getTransportTypes()); + getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes()); final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); - final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network); + final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.getNetwork()); final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED : getSubTypeForStateSnapshot(snapshot); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, @@ -1306,7 +1309,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Traffic occurring on the base interface is always counted for // both total usage and UID details. - final String baseIface = snapshot.linkProperties.getInterfaceName(); + final String baseIface = snapshot.getLinkProperties().getInterfaceName(); if (baseIface != null) { findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); @@ -1316,7 +1319,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // If IMS is metered, then the IMS network usage has already included VT usage. // VT is considered always metered in framework's layer. If VT is not metered // per carrier's policy, modem will report 0 usage for VT calls. - if (snapshot.networkCapabilities.hasCapability( + if (snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { // Copy the identify from IMS one but mark it as metered. @@ -1364,7 +1367,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // accounting is explicitly bypassed for traffic from the clat uid. // // TODO: This code might be combined to above code. - for (String iface : snapshot.linkProperties.getAllInterfaceNames()) { + for (String iface : snapshot.getLinkProperties().getAllInterfaceNames()) { // baseIface has been handled, so ignore it. if (TextUtils.equals(baseIface, iface)) continue; if (iface != null) { @@ -1383,11 +1386,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR"); } - final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier(); + final NetworkSpecifier spec = state.getNetworkCapabilities().getNetworkSpecifier(); if (spec instanceof TelephonyNetworkSpecifier) { return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); } else { @@ -1402,11 +1405,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * transport types do not actually fill this value. */ private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } - return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.subscriberId); + return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.getSubscriberId()); } private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet( diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index c01a1151ee67..29c3dd91c6a3 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -6850,7 +6850,7 @@ public class NotificationManagerService extends SystemService { .appendPath(record.getKey()).build()) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(EXTRA_KEY, record.getKey()), - PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, mSystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi); @@ -7713,6 +7713,21 @@ public class NotificationManagerService extends SystemService { int rank, int count, boolean wasPosted, String listenerName) { final String canceledKey = r.getKey(); + // Get pending intent used to create alarm, use FLAG_NO_CREATE if PendingIntent + // does not already exist, then null will be returned. + final PendingIntent pi = PendingIntent.getBroadcast(getContext(), + REQUEST_CODE_TIMEOUT, + new Intent(ACTION_NOTIFICATION_TIMEOUT) + .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT) + .appendPath(r.getKey()).build()) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND), + PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE); + + // Cancel alarm corresponding to pi. + if (pi != null) { + mAlarmManager.cancel(pi); + } + // Record caller. recordCallerLocked(r); diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java index 9a9e733cb390..da472be81156 100644 --- a/services/core/java/com/android/server/notification/SnoozeHelper.java +++ b/services/core/java/com/android/server/notification/SnoozeHelper.java @@ -37,6 +37,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.util.XmlUtils; +import com.android.server.pm.PackageManagerService; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -463,6 +464,7 @@ public class SnoozeHelper { return PendingIntent.getBroadcast(mContext, REQUEST_CODE_REPOST, new Intent(REPOST_ACTION) + .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME) .setData(new Uri.Builder().scheme(REPOST_SCHEME).appendPath(key).build()) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(EXTRA_KEY, key) diff --git a/services/core/java/com/android/server/os/OWNERS b/services/core/java/com/android/server/os/OWNERS new file mode 100644 index 000000000000..19573323e5ad --- /dev/null +++ b/services/core/java/com/android/server/os/OWNERS @@ -0,0 +1,2 @@ +# Bugreporting +per-file Bugreport* = file:/platform/frameworks/native:/cmds/dumpstate/OWNERS diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index c6a55b43d3fd..cb0af1117241 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -25,6 +25,7 @@ import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.ApexSessionParams; +import android.apex.CompressedApexInfoList; import android.apex.IApexService; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -357,6 +358,21 @@ public abstract class ApexManager { public abstract void markBootCompleted(); /** + * Estimate how much storage space is needed on /data/ for decompressing apexes + * @param infoList List of apexes that are compressed in target build. + * @return Size, in bytes, the amount of space needed on /data/ + */ + public abstract long calculateSizeForCompressedApex(CompressedApexInfoList infoList) + throws RemoteException; + + /** + * Reserve space on /data so that apexes can be decompressed after OTA + * @param infoList List of apexes that are compressed in target build. + */ + public abstract void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) + throws RemoteException; + + /** * Dumps various state information to the provided {@link PrintWriter} object. * * @param pw the {@link PrintWriter} object to send information to. @@ -898,6 +914,18 @@ public abstract class ApexManager { } } + @Override + public long calculateSizeForCompressedApex(CompressedApexInfoList infoList) + throws RemoteException { + return waitForApexService().calculateSizeForCompressedApex(infoList); + } + + @Override + public void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) + throws RemoteException { + waitForApexService().reserveSpaceForCompressedApex(infoList); + } + /** * Dump information about the packages contained in a particular cache * @param packagesCache the cache to print information about. @@ -1150,6 +1178,16 @@ public abstract class ApexManager { } @Override + public long calculateSizeForCompressedApex(CompressedApexInfoList infoList) { + throw new UnsupportedOperationException(); + } + + @Override + public void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) { + throw new UnsupportedOperationException(); + } + + @Override void dump(PrintWriter pw, String packageName) { // No-op } diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index acec93cac34d..77c1c1db2257 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -16,7 +16,6 @@ package com.android.server.pm; -import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.Nullable; @@ -24,12 +23,13 @@ import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; -import android.os.BatteryManager; +import android.os.BatteryManagerInternal; import android.os.Environment; import android.os.ServiceManager; import android.os.SystemProperties; @@ -37,6 +37,7 @@ import android.os.UserHandle; import android.os.storage.StorageManager; import android.util.ArraySet; import android.util.Log; +import android.util.Slog; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; @@ -65,9 +66,7 @@ public class BackgroundDexOptService extends JobService { private static final int JOB_IDLE_OPTIMIZE = 800; private static final int JOB_POST_BOOT_UPDATE = 801; - private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG - ? TimeUnit.MINUTES.toMillis(1) - : TimeUnit.DAYS.toMillis(1); + private static final long IDLE_OPTIMIZATION_PERIOD = TimeUnit.DAYS.toMillis(1); private static ComponentName sDexoptServiceName = new ComponentName( "android", @@ -115,14 +114,24 @@ public class BackgroundDexOptService extends JobService { return; } - JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + final JobScheduler js = context.getSystemService(JobScheduler.class); // Schedule a one-off job which scans installed packages and updates - // out-of-date oat files. - js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName) - .setMinimumLatency(TimeUnit.MINUTES.toMillis(1)) - .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1)) - .build()); + // out-of-date oat files. Schedule it 10 minutes after the boot complete event, + // so that we don't overload the boot with additional dex2oat compilations. + context.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName) + .setMinimumLatency(TimeUnit.MINUTES.toMillis(10)) + .setOverrideDeadline(TimeUnit.MINUTES.toMillis(60)) + .build()); + context.unregisterReceiver(this); + if (DEBUG) { + Slog.i(TAG, "BootBgDexopt scheduled"); + } + } + }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); // Schedule a daily job which scans installed packages and compiles // those with fresh profiling data. @@ -132,8 +141,8 @@ public class BackgroundDexOptService extends JobService { .setPeriodic(IDLE_OPTIMIZATION_PERIOD) .build()); - if (DEBUG_DEXOPT) { - Log.i(TAG, "Jobs scheduled"); + if (DEBUG) { + Slog.d(TAG, "BgDexopt scheduled"); } } @@ -149,32 +158,11 @@ public class BackgroundDexOptService extends JobService { } } - // Returns the current battery level as a 0-100 integer. - private int getBatteryLevel() { - IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - Intent intent = registerReceiver(null, filter); - int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); - - if (!present) { - // No battery, treat as if 100%, no possibility of draining battery. - return 100; - } - - if (level < 0 || scale <= 0) { - // Battery data unavailable. This should never happen, so assume the worst. - return 0; - } - - return (100 * level / scale); - } - private long getLowStorageThreshold(Context context) { @SuppressWarnings("deprecation") final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir); if (lowThreshold == 0) { - Log.e(TAG, "Invalid low storage threshold"); + Slog.e(TAG, "Invalid low storage threshold"); } return lowThreshold; @@ -198,9 +186,8 @@ public class BackgroundDexOptService extends JobService { private void postBootUpdate(JobParameters jobParams, PackageManagerService pm, ArraySet<String> pkgs) { - // Load low battery threshold from the system config. This is a 0-100 integer. - final int lowBatteryThreshold = getResources().getInteger( - com.android.internal.R.integer.config_lowBatteryWarningLevel); + final BatteryManagerInternal batteryManagerInternal = + LocalServices.getService(BatteryManagerInternal.class); final long lowThreshold = getLowStorageThreshold(this); mAbortPostBootUpdate.set(false); @@ -215,20 +202,19 @@ public class BackgroundDexOptService extends JobService { // Different job, which supersedes this one, is running. break; } - if (getBatteryLevel() < lowBatteryThreshold) { + if (batteryManagerInternal.getBatteryLevelLow()) { // Rather bail than completely drain the battery. break; } long usableSpace = mDataDir.getUsableSpace(); if (usableSpace < lowThreshold) { // Rather bail than completely fill up the disk. - Log.w(TAG, "Aborting background dex opt job due to low storage: " + + Slog.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace); break; } - - if (DEBUG_DEXOPT) { - Log.i(TAG, "Updating package " + pkg); + if (DEBUG) { + Slog.i(TAG, "Updating package " + pkg); } // Update package if needed. Note that there can be no race between concurrent @@ -260,13 +246,13 @@ public class BackgroundDexOptService extends JobService { public void run() { int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this); if (result == OPTIMIZE_PROCESSED) { - Log.i(TAG, "Idle optimizations completed."); + Slog.i(TAG, "Idle optimizations completed."); } else if (result == OPTIMIZE_ABORT_NO_SPACE_LEFT) { - Log.w(TAG, "Idle optimizations aborted because of space constraints."); + Slog.w(TAG, "Idle optimizations aborted because of space constraints."); } else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { - Log.w(TAG, "Idle optimizations aborted by job scheduler."); + Slog.w(TAG, "Idle optimizations aborted by job scheduler."); } else { - Log.w(TAG, "Idle optimizations ended with unexpected code: " + result); + Slog.w(TAG, "Idle optimizations ended with unexpected code: " + result); } if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { // Abandon our timeslice and do not reschedule. @@ -280,7 +266,7 @@ public class BackgroundDexOptService extends JobService { // Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes). private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs, Context context) { - Log.i(TAG, "Performing idle optimizations"); + Slog.i(TAG, "Performing idle optimizations"); // If post-boot update is still running, request that it exits early. mExitPostBootUpdate.set(true); mAbortIdleOptimization.set(false); @@ -355,11 +341,15 @@ public class BackgroundDexOptService extends JobService { final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE * lowStorageThreshold; boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade); - Log.d(TAG, "Should Downgrade " + shouldDowngrade); + if (DEBUG) { + Slog.d(TAG, "Should Downgrade " + shouldDowngrade); + } if (shouldDowngrade) { Set<String> unusedPackages = pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis); - Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages)); + if (DEBUG) { + Slog.d(TAG, "Unsused Packages " + String.join(",", unusedPackages)); + } if (!unusedPackages.isEmpty()) { for (String pkg : unusedPackages) { @@ -431,7 +421,9 @@ public class BackgroundDexOptService extends JobService { */ private boolean downgradePackage(PackageManagerService pm, String pkg, boolean isForPrimaryDex) { - Log.d(TAG, "Downgrading " + pkg); + if (DEBUG) { + Slog.d(TAG, "Downgrading " + pkg); + } boolean dex_opt_performed = false; int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE; int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE @@ -553,7 +545,7 @@ public class BackgroundDexOptService extends JobService { long usableSpace = mDataDir.getUsableSpace(); if (usableSpace < lowStorageThreshold) { // Rather bail than completely fill up the disk. - Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace); + Slog.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace); return OPTIMIZE_ABORT_NO_SPACE_LEFT; } @@ -592,8 +584,8 @@ public class BackgroundDexOptService extends JobService { @Override public boolean onStartJob(JobParameters params) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "onStartJob"); + if (DEBUG) { + Slog.i(TAG, "onStartJob"); } // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from @@ -601,17 +593,13 @@ public class BackgroundDexOptService extends JobService { // restart with a period of ~1 minute. PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package"); if (pm.isStorageLow()) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Low storage, skipping this run"); - } + Slog.i(TAG, "Low storage, skipping this run"); return false; } final ArraySet<String> pkgs = pm.getOptimizablePackages(); if (pkgs.isEmpty()) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "No packages to optimize"); - } + Slog.i(TAG, "No packages to optimize"); return false; } @@ -627,8 +615,8 @@ public class BackgroundDexOptService extends JobService { @Override public boolean onStopJob(JobParameters params) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "onStopJob"); + if (DEBUG) { + Slog.d(TAG, "onStopJob"); } if (params.getJobId() == JOB_POST_BOOT_UPDATE) { @@ -649,7 +637,7 @@ public class BackgroundDexOptService extends JobService { private void notifyPinService(ArraySet<String> updatedPackages) { PinnerService pinnerService = LocalServices.getService(PinnerService.class); if (pinnerService != null) { - Log.i(TAG, "Pinning optimized code " + updatedPackages); + Slog.i(TAG, "Pinning optimized code " + updatedPackages); pinnerService.update(updatedPackages, false /* force */); } } @@ -684,7 +672,7 @@ public class BackgroundDexOptService extends JobService { final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days"; String sysPropValue = SystemProperties.get(sysPropKey); if (sysPropValue == null || sysPropValue.isEmpty()) { - Log.w(TAG, "SysProp " + sysPropKey + " not set"); + Slog.w(TAG, "SysProp " + sysPropKey + " not set"); return Long.MAX_VALUE; } return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue)); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 48fee0b392a0..0d06426a7ab5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9962,6 +9962,8 @@ public class PackageManagerService extends IPackageManager.Stub public boolean performDexOptMode(String packageName, boolean checkProfiles, String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) { + enforceSystemOrRootOrShell("performDexOptMode"); + int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) | (force ? DexoptOptions.DEXOPT_FORCE : 0) | (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0); @@ -12528,6 +12530,7 @@ public class PackageManagerService extends IPackageManager.Stub if (hasOldPkg) { mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg, allPackageNames); + mPermissionManager.revokeStoragePermissionsIfScopeExpanded(pkg, oldPkg); } if (hasPermissionDefinitionChanges) { mPermissionManager.revokeRuntimePermissionsIfPermissionDefinitionChanged( diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 3ffca028b1c0..b500e1631fb5 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -206,6 +206,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { private static final int USER_PERMISSION_FLAGS = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED; + /** All storage permissions */ + private static final List<String> STORAGE_PERMISSIONS = new ArrayList<>(); + /** If the permission of the value is granted, so is the key */ private static final Map<String, String> FULLER_PERMISSION_MAP = new HashMap<>(); @@ -214,6 +217,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { Manifest.permission.ACCESS_FINE_LOCATION); FULLER_PERMISSION_MAP.put(Manifest.permission.INTERACT_ACROSS_USERS, Manifest.permission.INTERACT_ACROSS_USERS_FULL); + STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE); + STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION); } /** Lock to protect internal data access */ @@ -2266,6 +2272,49 @@ public class PermissionManagerService extends IPermissionManager.Stub { } /** + * If the app is updated, and has scoped storage permissions, then it is possible that the + * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions. + * @param newPackage The new package that was installed + * @param oldPackage The old package that was updated + */ + private void revokeStoragePermissionsIfScopeExpanded( + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage, + @NonNull PermissionCallback permissionCallback) { + boolean downgradedSdk = oldPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q + && newPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q; + boolean upgradedSdk = oldPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q + && newPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q; + boolean newlyRequestsLegacy = !upgradedSdk && !oldPackage.isRequestLegacyExternalStorage() + && newPackage.isRequestLegacyExternalStorage(); + + if (!newlyRequestsLegacy && !downgradedSdk) { + return; + } + + final int callingUid = Binder.getCallingUid(); + final int userId = UserHandle.getUserId(newPackage.getUid()); + int numRequestedPermissions = newPackage.getRequestedPermissions().size(); + for (int i = 0; i < numRequestedPermissions; i++) { + PermissionInfo permInfo = getPermissionInfo(newPackage.getRequestedPermissions().get(i), + newPackage.getPackageName(), 0); + if (permInfo == null || !STORAGE_PERMISSIONS.contains(permInfo.name)) { + continue; + } + + EventLog.writeEvent(0x534e4554, "171430330", newPackage.getUid(), + "Revoking permission " + permInfo.name + " from package " + + newPackage.getPackageName() + " as either the sdk downgraded " + + downgradedSdk + " or newly requested legacy full storage " + + newlyRequestsLegacy); + + revokeRuntimePermissionInternal(permInfo.name, newPackage.getPackageName(), + false, callingUid, userId, null, permissionCallback); + } + + } + + /** * We might auto-grant permissions if any permission of the group is already granted. Hence if * the group of a granted permission changes we need to revoke it to avoid having permissions of * the new group auto-granted. @@ -4734,6 +4783,19 @@ public class PermissionManagerService extends IPermissionManager.Stub { @UserIdInt int userId) { return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId); } + /** + * If the app is updated, and has scoped storage permissions, then it is possible that the + * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions. + * @param newPackage The new package that was installed + * @param oldPackage The old package that was updated + */ + public void revokeStoragePermissionsIfScopeExpanded( + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage + ) { + PermissionManagerService.this.revokeStoragePermissionsIfScopeExpanded(newPackage, + oldPackage, mDefaultPermissionCallback); + } @Override public void revokeRuntimePermissionsIfGroupChanged( diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 393e8527a991..a8e842f7ae92 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -266,6 +266,17 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager @NonNull ArrayList<String> allPackageNames); /** + * If the app is updated, and has scoped storage permissions, then it is possible that the + * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions. + * @param newPackage The new package that was installed + * @param oldPackage The old package that was updated + */ + public abstract void revokeStoragePermissionsIfScopeExpanded( + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage + ); + + /** * Add all permissions in the given package. * <p> * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index fa64df5b1670..836e6150414c 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5257,6 +5257,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { long[] pattern; switch (effectId) { case HapticFeedbackConstants.CONTEXT_CLICK: + case HapticFeedbackConstants.GESTURE_END: return VibrationEffect.get(VibrationEffect.EFFECT_TICK); case HapticFeedbackConstants.TEXT_HANDLE_MOVE: if (!mHapticTextHandleEnabled) { @@ -5269,7 +5270,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE: case HapticFeedbackConstants.ENTRY_BUMP: case HapticFeedbackConstants.DRAG_CROSSING: - case HapticFeedbackConstants.GESTURE_END: return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false); case HapticFeedbackConstants.KEYBOARD_TAP: // == KEYBOARD_PRESS case HapticFeedbackConstants.VIRTUAL_KEY: diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index 24337f3ad346..ed4a7bf107d1 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -24,10 +24,14 @@ import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMA import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_UNSPECIFIED; import static android.os.RecoverySystem.ResumeOnRebootRebootErrorCode; import static android.os.UserHandle.USER_SYSTEM; +import static android.ota.nano.OtaPackageMetadata.ApexMetadata; import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE; +import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER; import android.annotation.IntDef; +import android.apex.CompressedApexInfo; +import android.apex.CompressedApexInfoList; import android.content.Context; import android.content.IntentSender; import android.content.SharedPreferences; @@ -47,9 +51,11 @@ import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemProperties; import android.provider.DeviceConfig; +import android.sysprop.ApexProperties; import android.util.ArrayMap; import android.util.ArraySet; import android.util.FastImmutableArraySet; +import android.util.Log; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -59,6 +65,7 @@ import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.RebootEscrowListener; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.pm.ApexManager; import libcore.io.IoUtils; @@ -68,9 +75,13 @@ import java.io.File; import java.io.FileDescriptor; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; /** * The recovery system service is responsible for coordinating recovery related @@ -388,7 +399,13 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo @VisibleForTesting void onSystemServicesReady() { - mInjector.getLockSettingsService().setRebootEscrowListener(this); + LockSettingsInternal lockSettings = mInjector.getLockSettingsService(); + if (lockSettings == null) { + Slog.e(TAG, "Failed to get lock settings service, skipping set" + + " RebootEscrowListener"); + return; + } + lockSettings.setRebootEscrowListener(this); } @Override // Binder call @@ -554,12 +571,18 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo case ROR_NEED_PREPARATION: final long origId = Binder.clearCallingIdentity(); try { - boolean result = mInjector.getLockSettingsService().prepareRebootEscrow(); + LockSettingsInternal lockSettings = mInjector.getLockSettingsService(); + if (lockSettings == null) { + Slog.e(TAG, "Failed to get lock settings service, skipping" + + " prepareRebootEscrow"); + return false; + } // Clear the RoR preparation state if lock settings reports an failure. - if (!result) { + if (!lockSettings.prepareRebootEscrow()) { clearRoRPreparationState(); + return false; } - return result; + return true; } finally { Binder.restoreCallingIdentity(origId); } @@ -674,7 +697,14 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo case ROR_REQUESTED_NEED_CLEAR: final long origId = Binder.clearCallingIdentity(); try { - return mInjector.getLockSettingsService().clearRebootEscrow(); + LockSettingsInternal lockSettings = mInjector.getLockSettingsService(); + if (lockSettings == null) { + Slog.e(TAG, "Failed to get lock settings service, skipping" + + " clearRebootEscrow"); + return false; + } + + return lockSettings.clearRebootEscrow(); } finally { Binder.restoreCallingIdentity(origId); } @@ -768,7 +798,15 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo final long origId = Binder.clearCallingIdentity(); int providerErrorCode; try { - providerErrorCode = mInjector.getLockSettingsService().armRebootEscrow(); + LockSettingsInternal lockSettings = mInjector.getLockSettingsService(); + if (lockSettings == null) { + Slog.e(TAG, "Failed to get lock settings service, skipping" + + " armRebootEscrow"); + return new RebootPreparationError( + RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE, + ARM_REBOOT_ERROR_NO_PROVIDER); + } + providerErrorCode = lockSettings.armRebootEscrow(); } finally { Binder.restoreCallingIdentity(origId); } @@ -871,6 +909,76 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return rebootWithLskfImpl(packageName, reason, slotSwitch); } + public static boolean isUpdatableApexSupported() { + return ApexProperties.updatable().orElse(false); + } + + // Metadata should be no more than few MB, if it's larger than 100MB something is wrong. + private static final long APEX_INFO_SIZE_LIMIT = 24 * 1024 * 100; + + private static CompressedApexInfoList getCompressedApexInfoList(String packageFile) + throws IOException { + try (ZipFile zipFile = new ZipFile(packageFile)) { + final ZipEntry entry = zipFile.getEntry("apex_info.pb"); + if (entry == null) { + return null; + } + if (entry.getSize() >= APEX_INFO_SIZE_LIMIT) { + throw new IllegalArgumentException("apex_info.pb has size " + + entry.getSize() + + " which is larger than the permitted limit" + APEX_INFO_SIZE_LIMIT); + } + if (entry.getSize() == 0) { + CompressedApexInfoList infoList = new CompressedApexInfoList(); + infoList.apexInfos = new CompressedApexInfo[0]; + return infoList; + } + Log.i(TAG, "Allocating " + entry.getSize() + + " bytes of memory to store OTA Metadata"); + byte[] data = new byte[(int) entry.getSize()]; + + try (InputStream is = zipFile.getInputStream(entry)) { + int bytesRead = is.read(data); + String msg = "Read " + bytesRead + " when expecting " + data.length; + Log.e(TAG, msg); + if (bytesRead != data.length) { + throw new IOException(msg); + } + } + ApexMetadata metadata = ApexMetadata.parseFrom(data); + CompressedApexInfoList apexInfoList = new CompressedApexInfoList(); + apexInfoList.apexInfos = + Arrays.stream(metadata.apexInfo).filter(apex -> apex.isCompressed).map(apex -> { + CompressedApexInfo info = new CompressedApexInfo(); + info.moduleName = apex.packageName; + info.decompressedSize = apex.decompressedSize; + info.versionCode = apex.version; + return info; + }).toArray(CompressedApexInfo[]::new); + return apexInfoList; + } + } + + @Override + public boolean allocateSpaceForUpdate(String packageFile) { + if (!isUpdatableApexSupported()) { + Log.i(TAG, "Updatable Apex not supported, " + + "allocateSpaceForUpdate does nothing."); + return true; + } + try { + CompressedApexInfoList apexInfoList = getCompressedApexInfoList(packageFile); + ApexManager apexManager = ApexManager.getInstance(); + apexManager.reserveSpaceForCompressedApex(apexInfoList); + return true; + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } catch (IOException | UnsupportedOperationException e) { + Slog.e(TAG, "Failed to reserve space for compressed apex: ", e); + } + return false; + } + @Override // Binder call public boolean isLskfCaptured(String packageName) { enforcePermissionForResumeOnReboot(); diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java index 52ad893a9ace..823683655b81 100644 --- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java +++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java @@ -31,6 +31,7 @@ import android.telecom.DefaultDialerManager; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; import android.util.IntArray; import android.util.Slog; @@ -44,6 +45,9 @@ import com.android.server.SystemService; import com.android.server.pm.UserManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal; +import java.util.ArrayList; +import java.util.List; + /** * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup * to run in the system-server process so once it is loaded into memory it will stay running. @@ -208,13 +212,23 @@ public class TelecomLoaderService extends SystemService { return null; } } + SubscriptionManager subscriptionManager = + mContext.getSystemService(SubscriptionManager.class); + if (subscriptionManager == null) { + return null; + } TelecomManager telecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); - PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId); - if (phoneAccount != null) { - return new String[]{phoneAccount.getComponentName().getPackageName()}; + List<String> packages = new ArrayList<>(); + int[] subIds = subscriptionManager.getActiveSubscriptionIdList(); + for (int subId : subIds) { + PhoneAccountHandle phoneAccount = + telecomManager.getSimCallManagerForSubscription(subId); + if (phoneAccount != null) { + packages.add(phoneAccount.getComponentName().getPackageName()); + } } - return null; + return packages.toArray(new String[] {}); }); } diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java index 531136976c81..64ca85e3f09a 100644 --- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java +++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java @@ -286,6 +286,9 @@ public class TestHarnessModeService extends SystemService { private class TestHarnessModeShellCommand extends ShellCommand { @Override public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } switch (cmd) { case "enable": case "restore": diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index ff763fccd5ff..90b095bbbebe 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -39,6 +39,7 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.database.ContentObserver; import android.graphics.drawable.Drawable; +import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; import android.net.Uri; import android.os.Binder; @@ -185,8 +186,6 @@ public class TrustManagerService extends SystemService { private boolean mTrustAgentsCanRun = false; private int mCurrentUser = UserHandle.USER_SYSTEM; - private Authorization mAuthorizationService; - public TrustManagerService(Context context) { super(context); mContext = context; @@ -196,7 +195,6 @@ public class TrustManagerService extends SystemService { mStrongAuthTracker = new StrongAuthTracker(context); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); mSettingsObserver = new SettingsObserver(mHandler); - mAuthorizationService = new Authorization(); } @Override @@ -698,13 +696,14 @@ public class TrustManagerService extends SystemService { } if (changed) { dispatchDeviceLocked(userId, locked); - - Authorization.onLockScreenEvent(locked, userId, null); + Authorization.onLockScreenEvent(locked, userId, null, + getBiometricSids(userId)); // Also update the user's profiles who have unified challenge, since they // share the same unlocked state (see {@link #isDeviceLocked(int)}) for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) { if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) { - mAuthorizationService.onLockScreenEvent(locked, profileHandle, null); + Authorization.onLockScreenEvent(locked, profileHandle, null, + getBiometricSids(profileHandle)); } } } @@ -1044,6 +1043,14 @@ public class TrustManagerService extends SystemService { } } + private long[] getBiometricSids(int userId) { + BiometricManager biometricManager = mContext.getSystemService(BiometricManager.class); + if (biometricManager == null) { + return null; + } + return biometricManager.getAuthenticatorIds(userId); + } + // User lifecycle @Override @@ -1255,7 +1262,8 @@ public class TrustManagerService extends SystemService { mDeviceLockedForUser.put(userId, locked); } - Authorization.onLockScreenEvent(locked, userId, null); + Authorization.onLockScreenEvent(locked, userId, null, + getBiometricSids(userId)); if (locked) { try { diff --git a/services/core/java/com/android/server/vcn/OWNERS b/services/core/java/com/android/server/vcn/OWNERS index 33b9f0f75f81..2441e772468c 100644 --- a/services/core/java/com/android/server/vcn/OWNERS +++ b/services/core/java/com/android/server/vcn/OWNERS @@ -3,5 +3,5 @@ set noparent benedictwong@google.com ckesting@google.com evitayan@google.com +junyin@google.com nharold@google.com -jchalard@google.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java index 19fbdbd86099..5565ccb6cf7c 100644 --- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -145,7 +145,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { */ public void handleSubscriptionsChanged() { final Map<ParcelUuid, Set<String>> privilegedPackages = new HashMap<>(); - final Map<Integer, ParcelUuid> newSubIdToGroupMap = new HashMap<>(); + final Map<Integer, SubscriptionInfo> newSubIdToInfoMap = new HashMap<>(); final List<SubscriptionInfo> allSubs = mSubscriptionManager.getAllSubscriptionInfoList(); if (allSubs == null) { @@ -160,7 +160,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } // Build subId -> subGrp cache - newSubIdToGroupMap.put(subInfo.getSubscriptionId(), subInfo.getGroupUuid()); + newSubIdToInfoMap.put(subInfo.getSubscriptionId(), subInfo); // Update subscription groups that are both ready, and active. For a group to be // considered active, both of the following must be true: @@ -186,7 +186,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } final TelephonySubscriptionSnapshot newSnapshot = - new TelephonySubscriptionSnapshot(newSubIdToGroupMap, privilegedPackages); + new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages); // If snapshot was meaningfully updated, fire the callback if (!newSnapshot.equals(mCurrentSnapshot)) { @@ -245,7 +245,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ public static class TelephonySubscriptionSnapshot { - private final Map<Integer, ParcelUuid> mSubIdToGroupMap; + private final Map<Integer, SubscriptionInfo> mSubIdToInfoMap; private final Map<ParcelUuid, Set<String>> mPrivilegedPackages; public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = @@ -253,12 +253,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( - @NonNull Map<Integer, ParcelUuid> subIdToGroupMap, + @NonNull Map<Integer, SubscriptionInfo> subIdToInfoMap, @NonNull Map<ParcelUuid, Set<String>> privilegedPackages) { - Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null"); + Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null"); Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); - mSubIdToGroupMap = Collections.unmodifiableMap(subIdToGroupMap); + mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap); final Map<ParcelUuid, Set<String>> unmodifiableInnerSets = new ArrayMap<>(); for (Entry<ParcelUuid, Set<String>> entry : privilegedPackages.entrySet()) { @@ -285,7 +285,9 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** Returns the Subscription Group for a given subId. */ @Nullable public ParcelUuid getGroupForSubId(int subId) { - return mSubIdToGroupMap.get(subId); + return mSubIdToInfoMap.containsKey(subId) + ? mSubIdToInfoMap.get(subId).getGroupUuid() + : null; } /** @@ -295,8 +297,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { public Set<Integer> getAllSubIdsInGroup(ParcelUuid subGrp) { final Set<Integer> subIds = new ArraySet<>(); - for (Entry<Integer, ParcelUuid> entry : mSubIdToGroupMap.entrySet()) { - if (subGrp.equals(entry.getValue())) { + for (Entry<Integer, SubscriptionInfo> entry : mSubIdToInfoMap.entrySet()) { + if (subGrp.equals(entry.getValue().getGroupUuid())) { subIds.add(entry.getKey()); } } @@ -304,9 +306,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { return subIds; } + /** Checks if the requested subscription is opportunistic */ + @NonNull + public boolean isOpportunistic(int subId) { + return mSubIdToInfoMap.containsKey(subId) + ? mSubIdToInfoMap.get(subId).isOpportunistic() + : false; + } + @Override public int hashCode() { - return Objects.hash(mSubIdToGroupMap, mPrivilegedPackages); + return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages); } @Override @@ -317,7 +327,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj; - return mSubIdToGroupMap.equals(other.mSubIdToGroupMap) + return mSubIdToInfoMap.equals(other.mSubIdToInfoMap) && mPrivilegedPackages.equals(other.mPrivilegedPackages); } @@ -326,7 +336,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { pw.println("TelephonySubscriptionSnapshot:"); pw.increaseIndent(); - pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap); + pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap); pw.println("mPrivilegedPackages: " + mPrivilegedPackages); pw.decreaseIndent(); @@ -335,7 +345,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public String toString() { return "TelephonySubscriptionSnapshot{ " - + "mSubIdToGroupMap=" + mSubIdToGroupMap + + "mSubIdToInfoMap=" + mSubIdToInfoMap + ", mPrivilegedPackages=" + mPrivilegedPackages + " }"; } diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java index 88180239da67..b05662e1678e 100644 --- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -16,6 +16,10 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; + import android.annotation.NonNull; import android.annotation.Nullable; import android.net.ConnectivityManager; @@ -25,8 +29,16 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnManager; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.ParcelUuid; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -35,9 +47,13 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.TreeSet; /** * Tracks a set of Networks underpinning a VcnGatewayConnection. @@ -51,19 +67,62 @@ import java.util.Set; public class UnderlyingNetworkTracker { @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName(); + /** + * Minimum signal strength for a WiFi network to be eligible for switching to + * + * <p>A network that satisfies this is eligible to become the selected underlying network with + * no additional conditions + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70; + + /** + * Minimum signal strength to continue using a WiFi network + * + * <p>A network that satisfies the conditions may ONLY continue to be used if it is already + * selected as the underlying network. A WiFi network satisfying this condition, but NOT the + * prospective-network RSSI threshold CANNOT be switched to. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74; + + /** Priority for any cellular network for which the subscription is listed as opportunistic */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0; + + /** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_WIFI_IN_USE = 1; + + /** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_WIFI_PROSPECTIVE = 2; + + /** Priority for any standard macro cellular network */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_MACRO_CELLULAR = 3; + + /** Priority for any other networks (including unvalidated, etc) */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PRIORITY_ANY = Integer.MAX_VALUE; + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; - @NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities; @NonNull private final UnderlyingNetworkTrackerCallback mCb; @NonNull private final Dependencies mDeps; @NonNull private final Handler mHandler; @NonNull private final ConnectivityManager mConnectivityManager; + @NonNull private final TelephonyCallback mActiveDataSubIdListener = + new VcnActiveDataSubscriptionIdListener(); @NonNull private final List<NetworkCallback> mCellBringupCallbacks = new ArrayList<>(); @Nullable private NetworkCallback mWifiBringupCallback; - @Nullable private NetworkCallback mRouteSelectionCallback; + @Nullable private NetworkCallback mWifiEntryRssiThresholdCallback; + @Nullable private NetworkCallback mWifiExitRssiThresholdCallback; + @Nullable private UnderlyingNetworkListener mRouteSelectionCallback; @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; + @Nullable private PersistableBundle mCarrierConfig; private boolean mIsQuitting = false; @Nullable private UnderlyingNetworkRecord mCurrentRecord; @@ -73,13 +132,11 @@ public class UnderlyingNetworkTracker { @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull Set<Integer> requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb) { this( vcnContext, subscriptionGroup, snapshot, - requiredUnderlyingNetworkCapabilities, cb, new Dependencies()); } @@ -88,22 +145,41 @@ public class UnderlyingNetworkTracker { @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull TelephonySubscriptionSnapshot snapshot, - @NonNull Set<Integer> requiredUnderlyingNetworkCapabilities, @NonNull UnderlyingNetworkTrackerCallback cb, @NonNull Dependencies deps) { mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot"); - mRequiredUnderlyingNetworkCapabilities = - Objects.requireNonNull( - requiredUnderlyingNetworkCapabilities, - "Missing requiredUnderlyingNetworkCapabilities"); mCb = Objects.requireNonNull(cb, "Missing cb"); mDeps = Objects.requireNonNull(deps, "Missing deps"); mHandler = new Handler(mVcnContext.getLooper()); mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); + mVcnContext + .getContext() + .getSystemService(TelephonyManager.class) + .registerTelephonyCallback(new HandlerExecutor(mHandler), mActiveDataSubIdListener); + + // TODO: Listen for changes in carrier config that affect this. + for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { + PersistableBundle config = + mVcnContext + .getContext() + .getSystemService(CarrierConfigManager.class) + .getConfigForSubId(subId); + + if (config != null) { + mCarrierConfig = config; + + // Attempt to use (any) non-opportunistic subscription. If this subscription is + // opportunistic, continue and try to find a non-opportunistic subscription, using + // the opportunistic ones as a last resort. + if (!isOpportunistic(mLastSnapshot, Collections.singleton(subId))) { + break; + } + } + } registerOrUpdateNetworkRequests(); } @@ -111,16 +187,30 @@ public class UnderlyingNetworkTracker { private void registerOrUpdateNetworkRequests() { NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback; NetworkCallback oldWifiCallback = mWifiBringupCallback; + NetworkCallback oldWifiEntryRssiThresholdCallback = mWifiEntryRssiThresholdCallback; + NetworkCallback oldWifiExitRssiThresholdCallback = mWifiExitRssiThresholdCallback; List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); // Register new callbacks. Make-before-break; always register new callbacks before removal // of old callbacks if (!mIsQuitting) { - mRouteSelectionCallback = new RouteSelectionCallback(); - mConnectivityManager.requestBackgroundNetwork( + mRouteSelectionCallback = new UnderlyingNetworkListener(); + mConnectivityManager.registerNetworkCallback( getRouteSelectionRequest(), mRouteSelectionCallback, mHandler); + mWifiEntryRssiThresholdCallback = new NetworkBringupCallback(); + mConnectivityManager.registerNetworkCallback( + getWifiEntryRssiThresholdNetworkRequest(), + mWifiEntryRssiThresholdCallback, + mHandler); + + mWifiExitRssiThresholdCallback = new NetworkBringupCallback(); + mConnectivityManager.registerNetworkCallback( + getWifiExitRssiThresholdNetworkRequest(), + mWifiExitRssiThresholdCallback, + mHandler); + mWifiBringupCallback = new NetworkBringupCallback(); mConnectivityManager.requestBackgroundNetwork( getWifiNetworkRequest(), mWifiBringupCallback, mHandler); @@ -135,6 +225,8 @@ public class UnderlyingNetworkTracker { } else { mRouteSelectionCallback = null; mWifiBringupCallback = null; + mWifiEntryRssiThresholdCallback = null; + mWifiExitRssiThresholdCallback = null; // mCellBringupCallbacks already cleared above. } @@ -145,6 +237,12 @@ public class UnderlyingNetworkTracker { if (oldWifiCallback != null) { mConnectivityManager.unregisterNetworkCallback(oldWifiCallback); } + if (oldWifiEntryRssiThresholdCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldWifiEntryRssiThresholdCallback); + } + if (oldWifiExitRssiThresholdCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldWifiExitRssiThresholdCallback); + } for (NetworkCallback cellBringupCallback : oldCellCallbacks) { mConnectivityManager.unregisterNetworkCallback(cellBringupCallback); } @@ -158,9 +256,18 @@ public class UnderlyingNetworkTracker { * carrier owned networks may be selected, as the request specifies only subIds in the VCN's * subscription group, while the VCN networks are excluded by virtue of not having subIds set on * the VCN-exposed networks. + * + * <p>If the VCN that this UnderlyingNetworkTracker belongs to is in test-mode, this will return + * a NetworkRequest that only matches Test Networks. */ private NetworkRequest getRouteSelectionRequest() { + if (mVcnContext.isInTestMode()) { + return getTestNetworkRequest(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)); + } + return getBaseNetworkRequestBuilder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); } @@ -182,6 +289,38 @@ public class UnderlyingNetworkTracker { } /** + * Builds the WiFi entry threshold signal strength request + * + * <p>This request ensures that WiFi reports the crossing of the wifi entry RSSI threshold. + * Without this request, WiFi rate-limits, and reports signal strength changes at too slow a + * pace to effectively select a short-lived WiFi offload network. + */ + private NetworkRequest getWifiEntryRssiThresholdNetworkRequest() { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + // Ensure wifi updates signal strengths when crossing this threshold. + .setSignalStrength(getWifiEntryRssiThreshold(mCarrierConfig)) + .build(); + } + + /** + * Builds the WiFi exit threshold signal strength request + * + * <p>This request ensures that WiFi reports the crossing of the wifi exit RSSI threshold. + * Without this request, WiFi rate-limits, and reports signal strength changes at too slow a + * pace to effectively select away from a failing WiFi network. + */ + private NetworkRequest getWifiExitRssiThresholdNetworkRequest() { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + // Ensure wifi updates signal strengths when crossing this threshold. + .setSignalStrength(getWifiExitRssiThreshold(mCarrierConfig)) + .build(); + } + + /** * Builds a Cellular bringup request for a given subId * * <p>This request is filed in order to ensure that the Telephony stack always has a @@ -210,6 +349,15 @@ public class UnderlyingNetworkTracker { .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); } + /** Builds and returns a NetworkRequest for the given subIds to match Test Networks. */ + private NetworkRequest getTestNetworkRequest(@NonNull Set<Integer> subIds) { + return new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setSubscriptionIds(subIds) + .build(); + } + /** * Update this UnderlyingNetworkTracker's TelephonySubscriptionSnapshot. * @@ -217,10 +365,18 @@ public class UnderlyingNetworkTracker { * reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered * or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change. */ - public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { - Objects.requireNonNull(snapshot, "Missing snapshot"); + public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot newSnapshot) { + Objects.requireNonNull(newSnapshot, "Missing newSnapshot"); + + final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; + mLastSnapshot = newSnapshot; - mLastSnapshot = snapshot; + // Only trigger re-registration if subIds in this group have changed + if (oldSnapshot + .getAllSubIdsInGroup(mSubscriptionGroup) + .equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) { + return; + } registerOrUpdateNetworkRequests(); } @@ -231,88 +387,43 @@ public class UnderlyingNetworkTracker { // Will unregister all existing callbacks, but not register new ones due to quitting flag. registerOrUpdateNetworkRequests(); - } - - /** Returns whether the currently selected Network matches the given network. */ - private static boolean isSameNetwork( - @Nullable UnderlyingNetworkRecord.Builder recordInProgress, @NonNull Network network) { - return recordInProgress != null && recordInProgress.getNetwork().equals(network); - } - - /** Notify the Callback if a full UnderlyingNetworkRecord exists. */ - private void maybeNotifyCallback() { - // Only forward this update if a complete record has been received - if (!mRecordInProgress.isValid()) { - return; - } - - // Only forward this update if the updated record differs form the current record - UnderlyingNetworkRecord updatedRecord = mRecordInProgress.build(); - if (!updatedRecord.equals(mCurrentRecord)) { - mCurrentRecord = updatedRecord; - - mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); - } - } - - private void handleNetworkAvailable(@NonNull Network network) { - mVcnContext.ensureRunningOnLooperThread(); - - mRecordInProgress = new UnderlyingNetworkRecord.Builder(network); - } - - private void handleNetworkLost(@NonNull Network network) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Non-underlying Network lost"); - return; - } - mRecordInProgress = null; - mCurrentRecord = null; - mCb.onSelectedUnderlyingNetworkChanged(null /* underlyingNetworkRecord */); + mVcnContext + .getContext() + .getSystemService(TelephonyManager.class) + .unregisterTelephonyCallback(mActiveDataSubIdListener); } - private void handleCapabilitiesChanged( - @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - mVcnContext.ensureRunningOnLooperThread(); + private void reevaluateNetworks() { + TreeSet<UnderlyingNetworkRecord> sorted = + new TreeSet<>( + UnderlyingNetworkRecord.getComparator( + mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig)); + sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks()); - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to NetworkCapabilities"); + UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first(); + if (Objects.equals(mCurrentRecord, candidate)) { return; } - mRecordInProgress.setNetworkCapabilities(networkCapabilities); - - maybeNotifyCallback(); + mCurrentRecord = candidate; + mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); } - private void handlePropertiesChanged( - @NonNull Network network, @NonNull LinkProperties linkProperties) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to LinkProperties"); - return; + private static boolean isOpportunistic( + @NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) { + if (snapshot == null) { + Slog.wtf(TAG, "Got null snapshot"); + return false; } - mRecordInProgress.setLinkProperties(linkProperties); - - maybeNotifyCallback(); - } - - private void handleNetworkBlocked(@NonNull Network network, boolean isBlocked) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to isBlocked"); - return; + for (int subId : subIds) { + if (snapshot.isOpportunistic(subId)) { + return true; + } } - mRecordInProgress.setIsBlocked(isBlocked); - - maybeNotifyCallback(); + return false; } /** @@ -331,34 +442,102 @@ public class UnderlyingNetworkTracker { * truth. */ @VisibleForTesting - class RouteSelectionCallback extends NetworkCallback { + class UnderlyingNetworkListener extends NetworkCallback { + private final Map<Network, UnderlyingNetworkRecord.Builder> + mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); + + private List<UnderlyingNetworkRecord> getUnderlyingNetworks() { + final List<UnderlyingNetworkRecord> records = new ArrayList<>(); + + for (UnderlyingNetworkRecord.Builder builder : + mUnderlyingNetworkRecordBuilders.values()) { + if (builder.isValid()) { + records.add(builder.build()); + } + } + + return records; + } + @Override public void onAvailable(@NonNull Network network) { - handleNetworkAvailable(network); + mUnderlyingNetworkRecordBuilders.put( + network, new UnderlyingNetworkRecord.Builder(network)); } @Override public void onLost(@NonNull Network network) { - handleNetworkLost(network); + mUnderlyingNetworkRecordBuilders.remove(network); + + reevaluateNetworks(); } @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return; - handleCapabilitiesChanged(network, networkCapabilities); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got capabilities change for unknown key: " + network); + return; + } + + builder.setNetworkCapabilities(networkCapabilities); + if (builder.isValid()) { + reevaluateNetworks(); + } } @Override public void onLinkPropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { - handlePropertiesChanged(network, linkProperties); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got link properties change for unknown key: " + network); + return; + } + + builder.setLinkProperties(linkProperties); + if (builder.isValid()) { + reevaluateNetworks(); + } } @Override public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) { - handleNetworkBlocked(network, isBlocked); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got blocked status change for unknown key: " + network); + return; + } + + builder.setIsBlocked(isBlocked); + if (builder.isValid()) { + reevaluateNetworks(); + } + } + } + + private static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, + WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT); + } + + return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; + } + + private static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, + WIFI_EXIT_RSSI_THRESHOLD_DEFAULT); } + + return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; } /** A record of a single underlying network, caching relevant fields. */ @@ -397,6 +576,89 @@ public class UnderlyingNetworkTracker { return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); } + /** + * Gives networks a priority class, based on the following priorities: + * + * <ol> + * <li>Opportunistic cellular + * <li>Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT + * <li>Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT + * <li>Macro cellular + * <li>Any others + * </ol> + */ + private int calculatePriorityClass( + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + final NetworkCapabilities caps = networkCapabilities; + + // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED + + if (isBlocked) { + Slog.wtf(TAG, "Network blocked for System Server: " + network); + return PRIORITY_ANY; + } + + if (caps.hasTransport(TRANSPORT_CELLULAR) + && isOpportunistic(snapshot, caps.getSubscriptionIds())) { + // If this carrier is the active data provider, ensure that opportunistic is only + // ever prioritized if it is also the active data subscription. This ensures that + // if an opportunistic subscription is still in the process of being switched to, + // or switched away from, the VCN does not attempt to continue using it against the + // decision made at the telephony layer. Failure to do so may result in the modem + // switching back and forth. + // + // Allow the following two cases: + // 1. Active subId is NOT in the group that this VCN is supporting + // 2. This opportunistic subscription is for the active subId + if (!snapshot.getAllSubIdsInGroup(subscriptionGroup) + .contains(SubscriptionManager.getActiveDataSubscriptionId()) + || caps.getSubscriptionIds() + .contains(SubscriptionManager.getActiveDataSubscriptionId())) { + return PRIORITY_OPPORTUNISTIC_CELLULAR; + } + } + + if (caps.hasTransport(TRANSPORT_WIFI)) { + if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig) + && currentlySelected != null + && network.equals(currentlySelected.network)) { + return PRIORITY_WIFI_IN_USE; + } + + if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) { + return PRIORITY_WIFI_PROSPECTIVE; + } + } + + // Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might + // be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be + // the case if the Default Data SubId does not support certain services (eg voice + // calling) + if (caps.hasTransport(TRANSPORT_CELLULAR) + && !isOpportunistic(snapshot, caps.getSubscriptionIds())) { + return PRIORITY_MACRO_CELLULAR; + } + + return PRIORITY_ANY; + } + + private static Comparator<UnderlyingNetworkRecord> getComparator( + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + return (left, right) -> { + return Integer.compare( + left.calculatePriorityClass( + subscriptionGroup, snapshot, currentlySelected, carrierConfig), + right.calculatePriorityClass( + subscriptionGroup, snapshot, currentlySelected, carrierConfig)); + }; + } + /** Dumps the state of this record for logging and debugging purposes. */ public void dump(IndentingPrintWriter pw) { pw.println("UnderlyingNetworkRecord:"); @@ -418,6 +680,8 @@ public class UnderlyingNetworkTracker { boolean mIsBlocked; boolean mWasIsBlockedSet; + @Nullable private UnderlyingNetworkRecord mCached; + private Builder(@NonNull Network network) { mNetwork = network; } @@ -429,6 +693,7 @@ public class UnderlyingNetworkTracker { private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { mNetworkCapabilities = networkCapabilities; + mCached = null; } @Nullable @@ -438,11 +703,13 @@ public class UnderlyingNetworkTracker { private void setLinkProperties(@NonNull LinkProperties linkProperties) { mLinkProperties = linkProperties; + mCached = null; } private void setIsBlocked(boolean isBlocked) { mIsBlocked = isBlocked; mWasIsBlockedSet = true; + mCached = null; } private boolean isValid() { @@ -450,12 +717,30 @@ public class UnderlyingNetworkTracker { } private UnderlyingNetworkRecord build() { - return new UnderlyingNetworkRecord( - mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); + if (!isValid()) { + throw new IllegalArgumentException( + "Called build before UnderlyingNetworkRecord was valid"); + } + + if (mCached == null) { + mCached = + new UnderlyingNetworkRecord( + mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); + } + + return mCached; } } } + private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback + implements ActiveDataSubscriptionIdListener { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + reevaluateNetworks(); + } + } + /** Callbacks for being notified of the changes in, or to the selected underlying network. */ public interface UnderlyingNetworkTrackerCallback { /** diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index cccb0968fc6a..f918827e9639 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -50,6 +50,7 @@ import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.util.LogUtils; import java.util.Arrays; import java.util.Collections; @@ -305,13 +306,13 @@ public class Vcn extends Handler { handleTeardown(); break; default: - Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what); + logWtf("Unknown msg.what: " + msg.what); } } private void handleConfigUpdated(@NonNull VcnConfig config) { // TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode() - Slog.v(getLogTag(), "Config updated: config = " + config.hashCode()); + logDbg("Config updated: old = " + mConfig.hashCode() + "; new = " + config.hashCode()); mConfig = config; @@ -326,8 +327,7 @@ public class Vcn extends Handler { // connection details may have changed). if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) { if (gatewayConnection == null) { - Slog.wtf( - getLogTag(), "Found gatewayConnectionConfig without GatewayConnection"); + logWtf("Found gatewayConnectionConfig without GatewayConnection"); } else { gatewayConnection.teardownAsynchronously(); } @@ -340,6 +340,7 @@ public class Vcn extends Handler { } private void handleTeardown() { + logDbg("Tearing down"); mVcnContext.getVcnNetworkProvider().unregisterListener(mRequestListener); for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { @@ -350,6 +351,7 @@ public class Vcn extends Handler { } private void handleSafeModeStatusChanged() { + logDbg("VcnGatewayConnection safe mode status changed"); boolean hasSafeModeGatewayConnection = false; // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode @@ -365,21 +367,19 @@ public class Vcn extends Handler { hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE; if (oldStatus != mCurrentStatus) { mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection); + logDbg( + "Safe mode " + + (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited")); } } private void handleNetworkRequested(@NonNull NetworkRequest request) { - Slog.v(getLogTag(), "Received request " + request); + logVdbg("Received request " + request); // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - if (VDBG) { - Slog.v( - getLogTag(), - "Request already satisfied by existing VcnGatewayConnection: " - + request); - } + logDbg("Request already satisfied by existing VcnGatewayConnection: " + request); return; } } @@ -389,13 +389,23 @@ public class Vcn extends Handler { for (VcnGatewayConnectionConfig gatewayConnectionConfig : mConfig.getGatewayConnectionConfigs()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request); + logDbg("Bringing up new VcnGatewayConnection for request " + request); if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) { // Skip; this network does not provide any services if mobile data is disabled. continue; } + // This should never happen, by virtue of checking for the above check for + // pre-existing VcnGatewayConnections that satisfy a given request, but if state + // that affects the satsifying of requests changes, this is theoretically possible. + if (mVcnGatewayConnections.containsKey(gatewayConnectionConfig)) { + logWtf( + "Attempted to bring up VcnGatewayConnection for config " + + "with existing VcnGatewayConnection"); + return; + } + final VcnGatewayConnection vcnGatewayConnection = mDeps.newVcnGatewayConnection( mVcnContext, @@ -405,8 +415,12 @@ public class Vcn extends Handler { new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig), mIsMobileDataEnabled); mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); + + return; } } + + logVdbg("Request could not be fulfilled by VCN: " + request); } private Set<Integer> getExposedCapabilitiesForMobileDataState( @@ -423,7 +437,7 @@ public class Vcn extends Handler { } private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) { - Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config); + logDbg("VcnGatewayConnection quit: " + config); mVcnGatewayConnections.remove(config); // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied @@ -458,15 +472,18 @@ public class Vcn extends Handler { if (exposedCaps.contains(NET_CAPABILITY_INTERNET) || exposedCaps.contains(NET_CAPABILITY_DUN)) { if (gatewayConnection == null) { - Slog.wtf( - getLogTag(), - "Found gatewayConnectionConfig without GatewayConnection"); + logWtf("Found gatewayConnectionConfig without" + " GatewayConnection"); } else { // TODO(b/184868850): Optimize by restarting NetworkAgents without teardown. gatewayConnection.teardownAsynchronously(); } } } + + // Trigger re-evaluation of all requests; mobile data state impacts supported caps. + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + + logDbg("Mobile data " + (mIsMobileDataEnabled ? "enabled" : "disabled")); } } @@ -495,8 +512,38 @@ public class Vcn extends Handler { return request.canBeSatisfiedBy(builder.build()); } - private String getLogTag() { - return TAG + " [" + mSubscriptionGroup.hashCode() + "]"; + private String getLogPrefix() { + return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "]: "; + } + + private void logVdbg(String msg) { + if (VDBG) { + Slog.v(TAG, getLogPrefix() + msg); + } + } + + private void logDbg(String msg) { + Slog.d(TAG, getLogPrefix() + msg); + } + + private void logDbg(String msg, Throwable tr) { + Slog.d(TAG, getLogPrefix() + msg, tr); + } + + private void logErr(String msg) { + Slog.e(TAG, getLogPrefix() + msg); + } + + private void logErr(String msg, Throwable tr) { + Slog.e(TAG, getLogPrefix() + msg, tr); + } + + private void logWtf(String msg) { + Slog.wtf(TAG, getLogPrefix() + msg); + } + + private void logWtf(String msg, Throwable tr) { + Slog.wtf(TAG, getLogPrefix() + msg, tr); } /** @@ -509,6 +556,7 @@ public class Vcn extends Handler { pw.increaseIndent(); pw.println("mCurrentStatus: " + mCurrentStatus); + pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled); pw.println("mVcnGatewayConnections:"); for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) { diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java index 7399e56b3a95..d958222ea407 100644 --- a/services/core/java/com/android/server/vcn/VcnContext.java +++ b/services/core/java/com/android/server/vcn/VcnContext.java @@ -31,14 +31,17 @@ public class VcnContext { @NonNull private final Context mContext; @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; + private final boolean mIsInTestMode; public VcnContext( @NonNull Context context, @NonNull Looper looper, - @NonNull VcnNetworkProvider vcnNetworkProvider) { + @NonNull VcnNetworkProvider vcnNetworkProvider, + boolean isInTestMode) { mContext = Objects.requireNonNull(context, "Missing context"); mLooper = Objects.requireNonNull(looper, "Missing looper"); mVcnNetworkProvider = Objects.requireNonNull(vcnNetworkProvider, "Missing networkProvider"); + mIsInTestMode = isInTestMode; } @NonNull @@ -56,6 +59,10 @@ public class VcnContext { return mVcnNetworkProvider; } + public boolean isInTestMode() { + return mIsInTestMode; + } + /** * 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 6ca3c4b66024..dff04bfc6d7c 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -52,7 +52,6 @@ import android.net.NetworkProvider; import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; -import android.net.TunnelConnectionParams; import android.net.Uri; import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSessionCallback; @@ -89,6 +88,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; +import com.android.server.vcn.util.LogUtils; import com.android.server.vcn.util.MtuUtils; import java.io.IOException; @@ -673,7 +673,6 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext, subscriptionGroup, mLastSnapshot, - mConnectionConfig.getAllUnderlyingCapabilities(), mUnderlyingNetworkTrackerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); @@ -702,6 +701,7 @@ public class VcnGatewayConnection extends StateMachine { * <p>Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { + logDbg("Triggering async teardown"); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */); @@ -711,6 +711,8 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void onQuitting() { + logDbg("Quitting VcnGatewayConnection"); + // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. if (mTunnelIface != null) { mTunnelIface.close(); @@ -751,6 +753,10 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180132994): explore safely removing this Thread check mVcnContext.ensureRunningOnLooperThread(); + logDbg( + "Selected underlying network changed: " + + (underlying == null ? null : underlying.network)); + // TODO(b/179091925): Move the delayed-message handling to BaseState // If underlying is null, all underlying networks have been lost. Disconnect VCN after a @@ -775,6 +781,8 @@ public class VcnGatewayConnection extends StateMachine { if (!mIsQuitting) { mWakeLock.acquire(); + + logVdbg("Wakelock acquired: " + mWakeLock); } } @@ -782,6 +790,8 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext.ensureRunningOnLooperThread(); mWakeLock.release(); + + logVdbg("Wakelock released: " + mWakeLock); } /** @@ -799,8 +809,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what); @@ -808,8 +817,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what, Object obj) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what, obj); @@ -817,8 +825,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what, int arg1) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what, arg1); @@ -826,8 +833,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what, int arg1, int arg2) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what, arg1, arg2); @@ -835,8 +841,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(int what, int arg1, int arg2, Object obj) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(what, arg1, arg2, obj); @@ -844,8 +849,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void sendMessage(Message msg) { - Slog.wtf( - TAG, + logWtf( "sendMessage should not be used in VcnGatewayConnection. See" + " sendMessageAndAcquireWakeLock()"); super.sendMessage(msg); @@ -936,10 +940,14 @@ public class VcnGatewayConnection extends StateMachine { } private void setTeardownTimeoutAlarm() { + logVdbg("Setting teardown timeout alarm; mCurrentToken: " + mCurrentToken); + // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In // either case, there is nothing to cancel. if (mTeardownTimeoutAlarm != null) { - Slog.wtf(TAG, "mTeardownTimeoutAlarm should be null before being set"); + logWtf( + "mTeardownTimeoutAlarm should be null before being set; mCurrentToken: " + + mCurrentToken); } final Message delayedMessage = obtainMessage(EVENT_TEARDOWN_TIMEOUT_EXPIRED, mCurrentToken); @@ -951,6 +959,8 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelTeardownTimeoutAlarm() { + logVdbg("Cancelling teardown timeout alarm; mCurrentToken: " + mCurrentToken); + if (mTeardownTimeoutAlarm != null) { mTeardownTimeoutAlarm.cancel(); mTeardownTimeoutAlarm = null; @@ -961,6 +971,11 @@ public class VcnGatewayConnection extends StateMachine { } private void setDisconnectRequestAlarm() { + logVdbg( + "Setting alarm to disconnect due to underlying network loss;" + + " mCurrentToken: " + + mCurrentToken); + // Only schedule a NEW alarm if none is already set. if (mDisconnectRequestAlarm != null) { return; @@ -981,6 +996,11 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelDisconnectRequestAlarm() { + logVdbg( + "Cancelling alarm to disconnect due to underlying network loss;" + + " mCurrentToken: " + + mCurrentToken); + if (mDisconnectRequestAlarm != null) { mDisconnectRequestAlarm.cancel(); mDisconnectRequestAlarm = null; @@ -994,10 +1014,14 @@ public class VcnGatewayConnection extends StateMachine { } private void setRetryTimeoutAlarm(long delay) { + logVdbg("Setting retry alarm; mCurrentToken: " + mCurrentToken); + // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In // either case, there is nothing to cancel. if (mRetryTimeoutAlarm != null) { - Slog.wtf(TAG, "mRetryTimeoutAlarm should be null before being set"); + logWtf( + "mRetryTimeoutAlarm should be null before being set; mCurrentToken: " + + mCurrentToken); } final Message delayedMessage = obtainMessage(EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken); @@ -1005,6 +1029,8 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelRetryTimeoutAlarm() { + logVdbg("Cancel retry alarm; mCurrentToken: " + mCurrentToken); + if (mRetryTimeoutAlarm != null) { mRetryTimeoutAlarm.cancel(); mRetryTimeoutAlarm = null; @@ -1015,6 +1041,8 @@ public class VcnGatewayConnection extends StateMachine { @VisibleForTesting(visibility = Visibility.PRIVATE) void setSafeModeAlarm() { + logVdbg("Setting safe mode alarm; mCurrentToken: " + mCurrentToken); + // Only schedule a NEW alarm if none is already set. if (mSafeModeTimeoutAlarm != null) { return; @@ -1029,6 +1057,8 @@ public class VcnGatewayConnection extends StateMachine { } private void cancelSafeModeAlarm() { + logVdbg("Cancel safe mode alarm; mCurrentToken: " + mCurrentToken); + if (mSafeModeTimeoutAlarm != null) { mSafeModeTimeoutAlarm.cancel(); mSafeModeTimeoutAlarm = null; @@ -1093,6 +1123,14 @@ public class VcnGatewayConnection extends StateMachine { + exception.getMessage(); } + logDbg( + "Encountered error; code=" + + errorCode + + ", exceptionClass=" + + exceptionClass + + ", exceptionMessage=" + + exceptionMessage); + mGatewayStatusCallback.onGatewayConnectionError( mConnectionConfig.getGatewayConnectionName(), errorCode, @@ -1138,7 +1176,7 @@ public class VcnGatewayConnection extends StateMachine { try { enterState(); } catch (Exception e) { - Slog.wtf(TAG, "Uncaught exception", e); + logWtf("Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } @@ -1170,14 +1208,14 @@ public class VcnGatewayConnection extends StateMachine { public final boolean processMessage(Message msg) { final int token = msg.arg1; if (!isValidToken(token)) { - Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what); + logDbg("Message called with obsolete token: " + token + "; what: " + msg.what); return HANDLED; } try { processStateMsg(msg); } catch (Exception e) { - Slog.wtf(TAG, "Uncaught exception", e); + logWtf("Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } @@ -1195,7 +1233,7 @@ public class VcnGatewayConnection extends StateMachine { try { exitState(); } catch (Exception e) { - Slog.wtf(TAG, "Uncaught exception", e); + logWtf("Uncaught exception", e); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } @@ -1235,7 +1273,7 @@ public class VcnGatewayConnection extends StateMachine { protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) { // TODO(b/180526152): notify VcnStatusCallback for Network loss - Slog.v(TAG, "Tearing down. Cause: " + info.reason); + logDbg("Tearing down. Cause: " + info.reason); mIsQuitting = info.shouldQuit; teardownNetwork(); @@ -1251,6 +1289,7 @@ public class VcnGatewayConnection extends StateMachine { protected void handleSafeModeTimeoutExceeded() { mSafeModeTimeoutAlarm = null; + logDbg("Entering safe mode after timeout exceeded"); // Connectivity for this GatewayConnection is broken; tear down the Network. teardownNetwork(); @@ -1259,13 +1298,15 @@ public class VcnGatewayConnection extends StateMachine { } protected void logUnexpectedEvent(int what) { - Slog.d(TAG, String.format( - "Unexpected event code %d in state %s", what, this.getClass().getSimpleName())); + logDbg( + "Unexpected event code " + + what + + " in state " + + this.getClass().getSimpleName()); } protected void logWtfUnknownEvent(int what) { - Slog.wtf(TAG, String.format( - "Unknown event code %d in state %s", what, this.getClass().getSimpleName())); + logWtf("Unknown event code " + what + " in state " + this.getClass().getSimpleName()); } } @@ -1282,7 +1323,7 @@ public class VcnGatewayConnection extends StateMachine { } if (mIkeSession != null || mNetworkAgent != null) { - Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState"); + logWtf("Active IKE Session or NetworkAgent in DisconnectedState"); } cancelSafeModeAlarm(); @@ -1350,7 +1391,7 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void enterState() throws Exception { if (mIkeSession == null) { - Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state."); + logWtf("IKE session was already closed when entering Disconnecting state."); sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, mCurrentToken); return; } @@ -1437,7 +1478,7 @@ public class VcnGatewayConnection extends StateMachine { @Override protected void enterState() { if (mIkeSession != null) { - Slog.wtf(TAG, "ConnectingState entered with active session"); + logWtf("ConnectingState entered with active session"); // Attempt to recover. mIkeSession.kill(); @@ -1456,7 +1497,7 @@ public class VcnGatewayConnection extends StateMachine { if (oldUnderlying == null) { // This should never happen, but if it does, there's likely a nasty bug. - Slog.wtf(TAG, "Old underlying network was null in connected state. Bug?"); + logWtf("Old underlying network was null in connected state. Bug?"); } // If new underlying is null, all underlying networks have been lost; disconnect @@ -1551,16 +1592,29 @@ public class VcnGatewayConnection extends StateMachine { // new NetworkAgent replaces an old one before the unwanted() call // is processed. if (mNetworkAgent != agentRef) { - Slog.d(TAG, "unwanted() called on stale NetworkAgent"); + logDbg("unwanted() called on stale NetworkAgent"); return; } - Slog.d(TAG, "NetworkAgent was unwanted"); + logDbg("NetworkAgent was unwanted"); teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { - if (status == NetworkAgent.VALIDATION_STATUS_VALID) { - clearFailedAttemptCounterAndSafeModeAlarm(); + switch (status) { + case NetworkAgent.VALIDATION_STATUS_VALID: + clearFailedAttemptCounterAndSafeModeAlarm(); + break; + case NetworkAgent.VALIDATION_STATUS_NOT_VALID: + // Will only set a new alarm if no safe mode alarm is + // currently scheduled. + setSafeModeAlarm(); + break; + default: + logWtf( + "Unknown validation status " + + status + + "; ignoring"); + break; } } /* validationStatusCallback */); @@ -1589,13 +1643,26 @@ public class VcnGatewayConnection extends StateMachine { @NonNull Network underlyingNetwork, @NonNull IpSecTransform transform, int direction) { + if (direction != IpSecManager.DIRECTION_IN && direction != IpSecManager.DIRECTION_OUT) { + Slog.wtf(TAG, "Applying transform for unexpected direction: " + direction); + } + try { tunnelIface.setUnderlyingNetwork(underlyingNetwork); // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); + + // For inbound transforms, additionally allow forwarded traffic to bridge to DUN (as + // needed) + final Set<Integer> exposedCaps = mConnectionConfig.getAllExposedCapabilities(); + if (direction == IpSecManager.DIRECTION_IN + && exposedCaps.contains(NET_CAPABILITY_DUN)) { + mIpSecManager.applyTunnelModeTransform( + tunnelIface, IpSecManager.DIRECTION_FWD, transform); + } } catch (IOException e) { - Slog.d(TAG, "Transform application failed for network " + token, e); + logDbg("Transform application failed for network " + token, e); sessionLost(token, e); } } @@ -1629,7 +1696,7 @@ public class VcnGatewayConnection extends StateMachine { tunnelIface.removeAddress(address.getAddress(), address.getPrefixLength()); } } catch (IOException e) { - Slog.d(TAG, "Adding address to tunnel failed for token " + token, e); + logDbg("Adding address to tunnel failed for token " + token, e); sessionLost(token, e); } } @@ -1709,6 +1776,8 @@ public class VcnGatewayConnection extends StateMachine { } private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) { + logDbg("Migration completed: " + mUnderlying.network); + applyTransform( mCurrentToken, mTunnelIface, @@ -1731,6 +1800,8 @@ public class VcnGatewayConnection extends StateMachine { mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; if (mUnderlying == null) { + logDbg("Underlying network lost"); + // Ignored for now; a new network may be coming up. If none does, the delayed // NETWORK_LOST disconnect will be fired, and tear down the session + network. return; @@ -1739,7 +1810,7 @@ public class VcnGatewayConnection extends StateMachine { // mUnderlying assumed non-null, given check above. // If network changed, migrate. Otherwise, update any existing networkAgent. if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) { - Slog.v(TAG, "Migrating to new network: " + mUnderlying.network); + logDbg("Migrating to new network: " + mUnderlying.network); mIkeSession.setNetwork(mUnderlying.network); } else { // oldUnderlying is non-null & underlying network itself has not changed @@ -1790,7 +1861,7 @@ public class VcnGatewayConnection extends StateMachine { mFailedAttempts++; if (mUnderlying == null) { - Slog.wtf(TAG, "Underlying network was null in retry state"); + logWtf("Underlying network was null in retry state"); transitionTo(mDisconnectedState); } else { // Safe to blindly set up, as it is cancelled and cleared on exiting this state @@ -1838,7 +1909,7 @@ public class VcnGatewayConnection extends StateMachine { private long getNextRetryIntervalsMs() { final int retryDelayIndex = mFailedAttempts - 1; - final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs(); + final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMillis(); // Repeatedly use last item in retry timeout list. if (retryDelayIndex >= retryIntervalsMs.length) { @@ -1924,14 +1995,8 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, @Nullable UnderlyingNetworkRecord underlying) { - final TunnelConnectionParams tunnelParams = + final IkeTunnelConnectionParams ikeTunnelParams = gatewayConnectionConfig.getTunnelConnectionParams(); - if (!(tunnelParams instanceof IkeTunnelConnectionParams)) { - throw new IllegalStateException( - "TunnelConnectionParams is not IkeTunnelConnectionParams"); - } - - final IkeTunnelConnectionParams ikeTunnelParams = (IkeTunnelConnectionParams) tunnelParams; final LinkProperties lp = new LinkProperties(); lp.setInterfaceName(tunnelIface.getInterfaceName()); @@ -1966,25 +2031,25 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) { - Slog.v(TAG, "IkeOpened for token " + mToken); + logDbg("IkeOpened for token " + mToken); // Nothing to do here. } @Override public void onClosed() { - Slog.v(TAG, "IkeClosed for token " + mToken); + logDbg("IkeClosed for token " + mToken); sessionClosed(mToken, null); } @Override public void onClosedExceptionally(@NonNull IkeException exception) { - Slog.v(TAG, "IkeClosedExceptionally for token " + mToken, exception); + logDbg("IkeClosedExceptionally for token " + mToken, exception); sessionClosed(mToken, exception); } @Override public void onError(@NonNull IkeProtocolException exception) { - Slog.v(TAG, "IkeError for token " + mToken, exception); + logDbg("IkeError for token " + mToken, exception); // Non-fatal, log and continue. } } @@ -2001,7 +2066,7 @@ public class VcnGatewayConnection extends StateMachine { /** Internal proxy method for injecting of mocked ChildSessionConfiguration */ @VisibleForTesting(visibility = Visibility.PRIVATE) void onOpened(@NonNull VcnChildSessionConfiguration childConfig) { - Slog.v(TAG, "ChildOpened for token " + mToken); + logDbg("ChildOpened for token " + mToken); childOpened(mToken, childConfig); } @@ -2012,19 +2077,19 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onClosed() { - Slog.v(TAG, "ChildClosed for token " + mToken); + logDbg("ChildClosed for token " + mToken); sessionLost(mToken, null); } @Override public void onClosedExceptionally(@NonNull IkeException exception) { - Slog.v(TAG, "ChildClosedExceptionally for token " + mToken, exception); + logDbg("ChildClosedExceptionally for token " + mToken, exception); sessionLost(mToken, exception); } @Override public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) { - Slog.v(TAG, "ChildTransformCreated; Direction: " + direction + "; token " + mToken); + logDbg("ChildTransformCreated; Direction: " + direction + "; token " + mToken); childTransformCreated(mToken, transform, direction); } @@ -2032,7 +2097,7 @@ public class VcnGatewayConnection extends StateMachine { public void onIpSecTransformsMigrated( @NonNull IpSecTransform inIpSecTransform, @NonNull IpSecTransform outIpSecTransform) { - Slog.v(TAG, "ChildTransformsMigrated; token " + mToken); + logDbg("ChildTransformsMigrated; token " + mToken); migrationCompleted(mToken, inIpSecTransform, outIpSecTransform); } @@ -2040,10 +2105,48 @@ public class VcnGatewayConnection extends StateMachine { public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) { // Nothing to be done; no references to the IpSecTransform are held, and this transform // will be closed by the IKE library. - Slog.v(TAG, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken); + logDbg("ChildTransformDeleted; Direction: " + direction + "; for token " + mToken); } } + private String getLogPrefix() { + return "[" + + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + + "-" + + mConnectionConfig.getGatewayConnectionName() + + "]: "; + } + + private void logVdbg(String msg) { + if (VDBG) { + Slog.v(TAG, getLogPrefix() + msg); + } + } + + private void logDbg(String msg) { + Slog.d(TAG, getLogPrefix() + msg); + } + + private void logDbg(String msg, Throwable tr) { + Slog.d(TAG, getLogPrefix() + msg, tr); + } + + private void logErr(String msg) { + Slog.e(TAG, getLogPrefix() + msg); + } + + private void logErr(String msg, Throwable tr) { + Slog.e(TAG, getLogPrefix() + msg, tr); + } + + private void logWtf(String msg) { + Slog.wtf(TAG, getLogPrefix() + msg); + } + + private void logWtf(String msg, Throwable tr) { + Slog.wtf(TAG, getLogPrefix() + msg, tr); + } + /** * Dumps the state of this VcnGatewayConnection for logging and debugging purposes. * @@ -2138,32 +2241,16 @@ public class VcnGatewayConnection extends StateMachine { } private IkeSessionParams buildIkeParams(@NonNull Network network) { - final TunnelConnectionParams tunnelConnectionParams = + final IkeTunnelConnectionParams ikeTunnelConnectionParams = mConnectionConfig.getTunnelConnectionParams(); - - if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) { - final IkeTunnelConnectionParams ikeTunnelConnectionParams = - (IkeTunnelConnectionParams) tunnelConnectionParams; - final IkeSessionParams.Builder builder = - new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams()); - builder.setNetwork(network); - - return builder.build(); - } - - throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams"); + final IkeSessionParams.Builder builder = + new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams()); + builder.setNetwork(network); + return builder.build(); } private ChildSessionParams buildChildParams() { - final TunnelConnectionParams tunnelConnectionParams = - mConnectionConfig.getTunnelConnectionParams(); - - if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) { - return ((IkeTunnelConnectionParams) tunnelConnectionParams) - .getTunnelModeChildSessionParams(); - } - - throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams"); + return mConnectionConfig.getTunnelConnectionParams().getTunnelModeChildSessionParams(); } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -2186,13 +2273,11 @@ public class VcnGatewayConnection extends StateMachine { VcnContext vcnContext, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - Set<Integer> requiredUnderlyingNetworkCapabilities, UnderlyingNetworkTrackerCallback callback) { return new UnderlyingNetworkTracker( vcnContext, subscriptionGroup, snapshot, - requiredUnderlyingNetworkCapabilities, callback); } diff --git a/core/java/android/net/TunnelConnectionParams.java b/services/core/java/com/android/server/vcn/util/LogUtils.java index f5b35395b0bf..93728ceb27c5 100644 --- a/core/java/android/net/TunnelConnectionParams.java +++ b/services/core/java/com/android/server/vcn/util/LogUtils.java @@ -13,17 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.net; -/** - * TunnelConnectionParams represents a configuration to set up a tunnel connection. - * - * <p>Concrete implementations for a control plane protocol should implement this interface. - * Subclasses should be immutable data classes containing connection, authentication and - * authorization parameters required to establish a tunnel connection. - * - * @see android.net.ipsec.ike.IkeTunnelConnectionParams - */ -// TODO:b/186071626 Remove TunnelConnectionParams when non-updatable API stub can resolve -// IkeTunnelConnectionParams -public interface TunnelConnectionParams {} +package com.android.server.vcn.util; + +import android.annotation.Nullable; +import android.os.ParcelUuid; + +import com.android.internal.util.HexDump; + +/** @hide */ +public class LogUtils { + /** + * Returns the hash of the subscription group in hexadecimal format. + * + * @return the hexadecimal encoded string if uuid was non-null, else {@code null} + */ + @Nullable + public static String getHashedSubscriptionGroup(@Nullable ParcelUuid uuid) { + if (uuid == null) { + return null; + } + + return HexDump.toHexString(uuid.hashCode()); + } +} diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index c4a42ab7e7be..281d2c9ed992 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -512,7 +512,7 @@ public class LockTaskController { setStatusBarState(mLockTaskModeState, userId); setKeyguardState(mLockTaskModeState, userId); if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) { - lockKeyguardIfNeeded(); + lockKeyguardIfNeeded(userId); } if (getDevicePolicyManager() != null) { getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId); @@ -824,15 +824,15 @@ public class LockTaskController { * Helper method for locking the device immediately. This may be necessary when the device * leaves the pinned mode. */ - private void lockKeyguardIfNeeded() { - if (shouldLockKeyguard()) { + private void lockKeyguardIfNeeded(int userId) { + if (shouldLockKeyguard(userId)) { mWindowManager.lockNow(null); mWindowManager.dismissKeyguard(null /* callback */, null /* message */); getLockPatternUtils().requireCredentialEntry(USER_ALL); } } - private boolean shouldLockKeyguard() { + private boolean shouldLockKeyguard(int userId) { // This functionality should be kept consistent with // com.android.settings.security.ScreenPinningSettings (see b/127605586) try { @@ -842,7 +842,7 @@ public class LockTaskController { } catch (Settings.SettingNotFoundException e) { // Log to SafetyNet for b/127605586 android.util.EventLog.writeEvent(0x534e4554, "127605586", -1, ""); - return getLockPatternUtils().isSecure(USER_CURRENT); + return getLockPatternUtils().isSecure(userId); } } diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS index bbcc2c1e581b..e8050fa00aa6 100644 --- a/services/core/jni/OWNERS +++ b/services/core/jni/OWNERS @@ -29,3 +29,4 @@ per-file com_android_server_se_* = file:/core/java/android/se/OWNERS per-file com_android_server_security_* = file:/core/java/android/security/OWNERS per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS per-file com_android_server_vibrator_* = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file com_android_server_am_CachedAppOptimizer.cpp = timmurray@google.com, edgararriaga@google.com, dualli@google.com, carmenjackson@google.com, philipcuadra@google.com
\ No newline at end of file diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 736a6f68725e..8e3cb2594986 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -91,7 +91,6 @@ import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.UserManagerInternal.OWNER_TYPE_DEVICE_OWNER; import static android.os.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER; import static android.os.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE; -import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; import static android.provider.Telephony.Carriers.DPC_URI; import static android.provider.Telephony.Carriers.ENFORCE_KEY; @@ -195,6 +194,7 @@ import android.location.LocationManager; import android.media.AudioManager; import android.media.IAudioService; import android.net.ConnectivityManager; +import android.net.ConnectivitySettingsManager; import android.net.IIpConnectivityMetrics; import android.net.ProxyInfo; import android.net.Uri; @@ -15566,12 +15566,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return context.getResources().getString(R.string.config_managed_provisioning_package); } - private void putPrivateDnsSettings(@Nullable String mode, @Nullable String host) { + private void putPrivateDnsSettings(int mode, @Nullable String host) { // Set Private DNS settings using system permissions, as apps cannot write // to global settings. mInjector.binderWithCleanCallingIdentity(() -> { - mInjector.settingsGlobalPutString(PRIVATE_DNS_MODE, mode); - mInjector.settingsGlobalPutString(PRIVATE_DNS_SPECIFIER, host); + ConnectivitySettingsManager.setPrivateDnsMode(mContext, mode); + ConnectivitySettingsManager.setPrivateDnsHostname(mContext, host); }); } @@ -15592,7 +15592,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new IllegalArgumentException( "Host provided for opportunistic mode, but is not needed."); } - putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, null); + putPrivateDnsSettings(ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, + null); return PRIVATE_DNS_SET_NO_ERROR; case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: if (TextUtils.isEmpty(privateDnsHost) @@ -15604,7 +15605,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Connectivity check will have been performed in the DevicePolicyManager before // the call here. putPrivateDnsSettings( - ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, + ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, privateDnsHost); return PRIVATE_DNS_SET_NO_ERROR; default: @@ -15621,13 +15622,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Objects.requireNonNull(who, "ComponentName is null"); enforceDeviceOwner(who); - final String currentMode = ConnectivityManager.getPrivateDnsMode(mContext); + final int currentMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext); switch (currentMode) { - case ConnectivityManager.PRIVATE_DNS_MODE_OFF: + case ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF: return PRIVATE_DNS_MODE_OFF; - case ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC: + case ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC: return PRIVATE_DNS_MODE_OPPORTUNISTIC; - case ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: + case ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; } diff --git a/services/net/TEST_MAPPING b/services/net/TEST_MAPPING index 7025dd178e0f..7eca1f99e4ef 100644 --- a/services/net/TEST_MAPPING +++ b/services/net/TEST_MAPPING @@ -2,6 +2,9 @@ "imports": [ { "path": "frameworks/base/core/java/android/net" + }, + { + "path": "packages/modules/Wifi/framework" } ] -}
\ No newline at end of file +} diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 1208eccc69eb..9706d7f5f78d 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -23,11 +23,13 @@ import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ResolveInfo; import android.os.Handler; import android.os.IBinder.DeathRecipient; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UpdateEngine; import android.os.UpdateEngineCallback; import android.os.UserHandle; @@ -42,6 +44,9 @@ import com.android.server.wm.ActivityMetricsLaunchObserver; import com.android.server.wm.ActivityMetricsLaunchObserverRegistry; import com.android.server.wm.ActivityTaskManagerInternal; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -75,7 +80,7 @@ public final class ProfcollectForwardingService extends SystemService { */ public static boolean enabled() { return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, "enabled", - false); + false) || SystemProperties.getBoolean("persist.profcollectd.enabled_override", false); } @Override @@ -297,24 +302,20 @@ public final class ProfcollectForwardingService extends SystemService { return; } - final boolean uploadReport = - DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, - "upload_report", false); - new Thread(() -> { try { String reportUuid = mIProfcollect.report(); - if (!uploadReport) { + final int profileId = getBBProfileId(); + String reportDir = "/data/user/" + profileId + + "/com.google.android.apps.internal.betterbug/cache/"; + String reportPath = reportDir + reportUuid + ".zip"; + + if (!Files.exists(Paths.get(reportDir))) { + Log.i(LOG_TAG, "Destination directory does not exist, abort upload."); return; } - final int profileId = getBBProfileId(); - mIProfcollect.copy_report_to_bb(profileId, reportUuid); - String reportPath = - "/data/user/" + profileId - + "/com.google.android.apps.internal.betterbug/cache/" - + reportUuid + ".zip"; Intent uploadIntent = new Intent("com.google.android.apps.betterbug.intent.action.UPLOAD_PROFILE") .setPackage("com.google.android.apps.internal.betterbug") @@ -323,9 +324,15 @@ public final class ProfcollectForwardingService extends SystemService { .putExtra("EXTRA_PROFILE_PATH", reportPath) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); Context context = getContext(); - if (context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0) != null) { - context.sendBroadcast(uploadIntent); + + List<ResolveInfo> receivers = + context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0); + if (receivers == null || receivers.isEmpty()) { + Log.i(LOG_TAG, "No one to receive upload intent, abort upload."); + return; } + mIProfcollect.copy_report_to_bb(profileId, reportUuid); + context.sendBroadcast(uploadIntent); mIProfcollect.delete_report(reportUuid); } catch (RemoteException e) { Log.e(LOG_TAG, e.getMessage()); diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java index 7bdc87ef6bd7..6b9aa18b9f8f 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -115,7 +115,12 @@ class CompatConfigBuilder { return this; } - CompatConfigBuilder addOverridableChangeWithId(long id) { + CompatConfigBuilder addEnabledOverridableChangeWithId(long id) { + mChanges.add(new CompatChange(id, "", -1, -1, false, false, "", true)); + return this; + } + + CompatConfigBuilder addDisabledOverridableChangeWithId(long id) { mChanges.add(new CompatChange(id, "", -1, -1, true, false, "", true)); return this; } diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java index a866363f46e6..0248b9b88788 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -36,6 +36,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; import org.junit.Before; import org.junit.Test; @@ -50,6 +51,10 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.UUID; @RunWith(AndroidJUnit4.class) @@ -249,7 +254,7 @@ public class CompatConfigTest { when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) .thenReturn(applicationInfo); - // Force the validator to prevent overriding the change by using a user build. + // Force the validator to prevent overriding non-overridable changes by using a user build. when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(true); @@ -261,10 +266,12 @@ public class CompatConfigTest { @Test public void testInstallerCanSetOverrides() throws Exception { - final long changeId = 1234L; - final int installerUid = 23; + final long disabledChangeId1 = 1234L; + final long disabledChangeId2 = 1235L; + // We make disabledChangeId2 non-overridable to make sure it is ignored. CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) - .addOverridableChangeWithId(1234L) + .addDisabledOverridableChangeWithId(disabledChangeId1) + .addDisabledChangeWithId(disabledChangeId2) .build(); ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() .withPackageName("com.some.package") @@ -274,19 +281,56 @@ public class CompatConfigTest { when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) .thenReturn(applicationInfo); - // Force the validator to prevent overriding the change by using a user build. + // Force the validator to prevent overriding non-overridable changes by using a user build. when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(true); CompatibilityOverrideConfig config = new CompatibilityOverrideConfig( - Collections.singletonMap(1234L, + Collections.singletonMap(disabledChangeId1, new PackageOverride.Builder() .setMaxVersionCode(99L) .setEnabled(true) .build())); compatConfig.addOverrides(config, "com.some.package"); - assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isFalse(); + } + + @Test + public void testPreventInstallerSetNonOverridable() throws Exception { + final long disabledChangeId1 = 1234L; + final long disabledChangeId2 = 1235L; + final long disabledChangeId3 = 1236L; + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledOverridableChangeWithId(disabledChangeId1) + .addDisabledChangeWithId(disabledChangeId2) + .addDisabledOverridableChangeWithId(disabledChangeId3) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + PackageManager packageManager = mock(PackageManager.class); + when(mContext.getPackageManager()).thenReturn(packageManager); + when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + // Force the validator to prevent overriding non-overridable changes by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + Map<Long, PackageOverride> overrides = new HashMap<>(); + overrides.put(disabledChangeId1, new PackageOverride.Builder().setEnabled(true).build()); + overrides.put(disabledChangeId2, new PackageOverride.Builder().setEnabled(true).build()); + overrides.put(disabledChangeId3, new PackageOverride.Builder().setEnabled(true).build()); + CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides); + + assertThrows(SecurityException.class, + () -> compatConfig.addOverrides(config, "com.some.package") + ); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isFalse(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isFalse(); } @Test @@ -459,7 +503,7 @@ public class CompatConfigTest { assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); // Reject all override attempts. - // Force the validator to prevent overriding the change by using a user build. + // Force the validator to prevent overriding non-overridable changes by using a user build. when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(false); // Try to turn off change, but validator prevents it. @@ -481,7 +525,7 @@ public class CompatConfigTest { .thenReturn(applicationInfo); // Reject all override attempts. - // Force the validator to prevent overriding the change by using a user build. + // Force the validator to prevent overriding non-overridable changes by using a user build. when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(true); // Try to remove a non existing override, and it doesn't fail. @@ -509,6 +553,90 @@ public class CompatConfigTest { } @Test + public void testInstallerCanRemoveOverrides() throws Exception { + final long disabledChangeId1 = 1234L; + final long disabledChangeId2 = 1235L; + final long enabledChangeId = 1236L; + // We make disabledChangeId2 non-overridable to make sure it is ignored. + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledOverridableChangeWithId(disabledChangeId1) + .addDisabledChangeWithId(disabledChangeId2) + .addEnabledOverridableChangeWithId(enabledChangeId) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + assertThat(compatConfig.addOverride(disabledChangeId1, "com.some.package", true)).isTrue(); + assertThat(compatConfig.addOverride(disabledChangeId2, "com.some.package", true)).isTrue(); + assertThat(compatConfig.addOverride(enabledChangeId, "com.some.package", false)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo)).isFalse(); + + // Force the validator to prevent overriding non-overridable changes by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + Set<Long> overridesToRemove = new HashSet<>(); + overridesToRemove.add(disabledChangeId1); + overridesToRemove.add(enabledChangeId); + CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig( + overridesToRemove); + + compatConfig.removePackageOverrides(config, "com.some.package"); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isFalse(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo)).isTrue(); + } + + @Test + public void testPreventInstallerRemoveNonOverridable() throws Exception { + final long disabledChangeId1 = 1234L; + final long disabledChangeId2 = 1235L; + final long disabledChangeId3 = 1236L; + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledOverridableChangeWithId(disabledChangeId1) + .addDisabledChangeWithId(disabledChangeId2) + .addDisabledOverridableChangeWithId(disabledChangeId3) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + PackageManager packageManager = mock(PackageManager.class); + when(mContext.getPackageManager()).thenReturn(packageManager); + when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + assertThat(compatConfig.addOverride(disabledChangeId1, "com.some.package", true)).isTrue(); + assertThat(compatConfig.addOverride(disabledChangeId2, "com.some.package", true)).isTrue(); + assertThat(compatConfig.addOverride(disabledChangeId3, "com.some.package", true)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isTrue(); + + // Force the validator to prevent overriding non-overridable changes by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + Set<Long> overridesToRemove = new HashSet<>(); + overridesToRemove.add(disabledChangeId1); + overridesToRemove.add(disabledChangeId2); + overridesToRemove.add(disabledChangeId3); + CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig( + overridesToRemove); + + assertThrows(SecurityException.class, + () -> compatConfig.removePackageOverrides(config, "com.some.package") + ); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isFalse(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isTrue(); + } + + @Test public void testEnableTargetSdkChangesForPackage() throws Exception { CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) .addEnabledChangeWithId(1L) diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index a2664e5f3b0a..9accd49bc392 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -98,7 +98,7 @@ public class PlatformCompatTest { .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.Q, 5L) .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.R, 6L) .addLoggingOnlyChangeWithId(7L) - .addOverridableChangeWithId(8L) + .addDisabledOverridableChangeWithId(8L) .build(); mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly( diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index deaeb46c4074..a1bce52fe63a 100644 --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -374,7 +374,7 @@ public class JobStoreTest { .setPersisted(true) .setRequiredNetwork(new NetworkRequest.Builder() .addCapability(NET_CAPABILITY_IMS) - .addUnwantedCapability(NET_CAPABILITY_OEM_PAID) + .addForbiddenCapability(NET_CAPABILITY_OEM_PAID) .build()) .build()); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 41562bb52a8d..a8b10f62d89a 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -155,7 +155,8 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override - public ManagedProfilePasswordCache getManagedProfilePasswordCache() { + public ManagedProfilePasswordCache getManagedProfilePasswordCache( + java.security.KeyStore ks) { return mock(ManagedProfilePasswordCache.class); } diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index e9e24866f35c..a02a039c3beb 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -1091,7 +1091,7 @@ public class NetworkPolicyManagerServiceTest { // first, pretend that wifi network comes online. no policy active, // which means we shouldn't push limit to interface. snapshots = List.of(buildWifi()); - when(mConnManager.getAllNetworkStateSnapshot()).thenReturn(snapshots); + when(mConnManager.getAllNetworkStateSnapshots()).thenReturn(snapshots); mPolicyListener.expect().onMeteredIfacesChanged(any()); mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); @@ -1099,7 +1099,7 @@ public class NetworkPolicyManagerServiceTest { // now change cycle to be on 15th, and test in early march, to verify we // pick cycle day in previous month. - when(mConnManager.getAllNetworkStateSnapshot()).thenReturn(snapshots); + when(mConnManager.getAllNetworkStateSnapshots()).thenReturn(snapshots); // pretend that 512 bytes total have happened stats = new NetworkStats(getElapsedRealtime(), 1) @@ -1360,7 +1360,7 @@ public class NetworkPolicyManagerServiceTest { .insertEntry(TEST_IFACE, 0L, 0L, 0L, 0L); { - when(mConnManager.getAllNetworkStateSnapshot()).thenReturn(snapshots); + when(mConnManager.getAllNetworkStateSnapshots()).thenReturn(snapshots); when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())).thenReturn(stats.getTotalBytes()); @@ -1483,7 +1483,7 @@ public class NetworkPolicyManagerServiceTest { } private PersistableBundle setupUpdateMobilePolicyCycleTests() throws RemoteException { - when(mConnManager.getAllNetworkStateSnapshot()) + when(mConnManager.getAllNetworkStateSnapshots()) .thenReturn(new ArrayList<NetworkStateSnapshot>()); setupTelephonySubscriptionManagers(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID); @@ -1496,7 +1496,7 @@ public class NetworkPolicyManagerServiceTest { @Test public void testUpdateMobilePolicyCycleWithNullConfig() throws RemoteException { - when(mConnManager.getAllNetworkStateSnapshot()) + when(mConnManager.getAllNetworkStateSnapshots()) .thenReturn(new ArrayList<NetworkStateSnapshot>()); setupTelephonySubscriptionManagers(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID); @@ -2089,7 +2089,7 @@ public class NetworkPolicyManagerServiceTest { new Network(TEST_NET_ID), buildNetworkCapabilities(TEST_SUB_ID, roaming), buildLinkProperties(TEST_IFACE), TEST_IMSI, TYPE_MOBILE)); - when(mConnManager.getAllNetworkStateSnapshot()).thenReturn(snapshots); + when(mConnManager.getAllNetworkStateSnapshots()).thenReturn(snapshots); } private void expectDefaultCarrierConfig() throws Exception { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 3deeea2d4577..c2ead5f15ceb 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java @@ -49,6 +49,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.FastXmlSerializer; import com.android.server.UiServiceTestCase; +import com.android.server.pm.PackageManagerService; import org.junit.Before; import org.junit.Test; @@ -257,6 +258,17 @@ public class SnoozeHelperTest extends UiServiceTestCase { } @Test + public void testSnoozeSentToAndroid() throws Exception { + NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r, 1000); + ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class); + verify(mAm, times(1)).setExactAndAllowWhileIdle( + anyInt(), anyLong(), captor.capture()); + assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, + captor.getValue().getIntent().getPackage()); + } + + @Test public void testSnooze() throws Exception { NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); mSnoozeHelper.snooze(r, (String) null); diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index e345becf0499..fdc01b48398f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -450,7 +450,7 @@ public class LockTaskControllerTest { Settings.Secure.clearProviderForTest(); // AND a password is set - when(mLockPatternUtils.isSecure(anyInt())) + when(mLockPatternUtils.isSecure(TEST_USER_ID)) .thenReturn(true); // AND there is a task record diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java index 7988b036ccd3..b980d3f55d2c 100644 --- a/telecomm/java/android/telecom/CallScreeningService.java +++ b/telecomm/java/android/telecom/CallScreeningService.java @@ -305,7 +305,7 @@ public abstract class CallScreeningService extends Service { * called with {@code false}, and all other parameters in this builder will be ignored. * <p> * This request will only be honored if the {@link CallScreeningService} shares the same - * uid as the default dialer app. Otherwise, the call will go through as usual. + * uid as the system dialer app. Otherwise, the call will go through as usual. * <p> * Apps built with SDK version {@link android.os.Build.VERSION_CODES#R} or later which * are using the microphone as part of audio processing should specify the diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java index 2983e6339d4b..a63ee4664378 100644 --- a/telecomm/java/android/telecom/CallerInfo.java +++ b/telecomm/java/android/telecom/CallerInfo.java @@ -406,8 +406,7 @@ public class CallerInfo { // Change the callerInfo number ONLY if it is an emergency number // or if it is the voicemail number. If it is either, take a // shortcut and skip the query. - TelephonyManager tm = context.getSystemService(TelephonyManager.class); - if (tm.isEmergencyNumber(number)) { + if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) { return new CallerInfo().markAsEmergency(context); } else if (PhoneNumberUtils.isVoiceMailNumber(null, subId, number)) { return new CallerInfo().markAsVoiceMail(context, subId); diff --git a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java index a9e1a8fc1952..bf49f3c7b9bf 100644 --- a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java +++ b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java @@ -483,7 +483,16 @@ public class CallerInfoAsyncQuery { // check to see if these are recognized numbers, and use shortcuts if we can. TelephonyManager tm = context.getSystemService(TelephonyManager.class); - if (tm.isEmergencyNumber(number)) { + boolean isEmergencyNumber = false; + try { + isEmergencyNumber = tm.isEmergencyNumber(number); + } catch (IllegalStateException ise) { + // Ignore the exception that Telephony is not up. Use PhoneNumberUtils API now. + // Ideally the PhoneNumberUtils API needs to be removed once the + // telphony service not up issue can be fixed (b/187412989) + isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(context, number); + } + if (isEmergencyNumber) { cw.event = EVENT_EMERGENCY_NUMBER; } else if (PhoneNumberUtils.isVoiceMailNumber(context, subId, number)) { cw.event = EVENT_VOICEMAIL_NUMBER; diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java index 4aa3614fa004..e2fb6019f30a 100644 --- a/telecomm/java/android/telecom/Logging/Session.java +++ b/telecomm/java/android/telecom/Logging/Session.java @@ -453,19 +453,19 @@ public class Session { @Override public String toString() { - if (mParentSession != null && mIsStartedFromActiveSession) { + Session sessionToPrint = this; + if (getParentSession() != null && isStartedFromActiveSession()) { // Log.startSession was called from within another active session. Use the parent's // Id instead of the child to reduce confusion. - return mParentSession.toString(); - } else { - StringBuilder methodName = new StringBuilder(); - methodName.append(getFullMethodPath(false /*truncatePath*/)); - if (mOwnerInfo != null && !mOwnerInfo.isEmpty()) { - methodName.append("("); - methodName.append(mOwnerInfo); - methodName.append(")"); - } - return methodName.toString() + "@" + getFullSessionId(); + sessionToPrint = getRootSession("toString"); + } + StringBuilder methodName = new StringBuilder(); + methodName.append(sessionToPrint.getFullMethodPath(false /*truncatePath*/)); + if (sessionToPrint.getOwnerInfo() != null && !sessionToPrint.getOwnerInfo().isEmpty()) { + methodName.append("("); + methodName.append(sessionToPrint.getOwnerInfo()); + methodName.append(")"); } + return methodName.toString() + "@" + sessionToPrint.getFullSessionId(); } } diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java index 25b062f85d3e..502bfa3749eb 100644 --- a/telephony/common/android/telephony/LocationAccessPolicy.java +++ b/telephony/common/android/telephony/LocationAccessPolicy.java @@ -86,8 +86,9 @@ public final class LocationAccessPolicy { private String mCallingFeatureId; private int mCallingUid; private int mCallingPid; - private int mMinSdkVersionForCoarse = Integer.MAX_VALUE; - private int mMinSdkVersionForFine = Integer.MAX_VALUE; + private int mMinSdkVersionForCoarse = -1; + private int mMinSdkVersionForFine = -1; + private int mMinSdkVersionForEnforcement = -1; private boolean mLogAsInfo = false; private String mMethod; @@ -125,7 +126,14 @@ public final class LocationAccessPolicy { /** * Apps that target at least this sdk version will be checked for coarse location - * permission. Defaults to INT_MAX (which means don't check) + * permission. This method MUST be called before calling {@link #build()}. Otherwise, an + * {@link IllegalArgumentException} will be thrown. + * + * Additionally, if both the argument to this method and + * {@link #setMinSdkVersionForFine} are greater than {@link Build.VERSION_CODES#BASE}, + * you must call {@link #setMinSdkVersionForEnforcement} with the min of the two to + * affirm that you do not want any location checks below a certain SDK version. + * Otherwise, {@link #build} will throw an {@link IllegalArgumentException}. */ public Builder setMinSdkVersionForCoarse( int minSdkVersionForCoarse) { @@ -135,7 +143,14 @@ public final class LocationAccessPolicy { /** * Apps that target at least this sdk version will be checked for fine location - * permission. Defaults to INT_MAX (which means don't check) + * permission. This method MUST be called before calling {@link #build()}. + * Otherwise, an {@link IllegalArgumentException} will be thrown. + * + * Additionally, if both the argument to this method and + * {@link #setMinSdkVersionForCoarse} are greater than {@link Build.VERSION_CODES#BASE}, + * you must call {@link #setMinSdkVersionForEnforcement} with the min of the two to + * affirm that you do not want any location checks below a certain SDK version. + * Otherwise, {@link #build} will throw an {@link IllegalArgumentException}. */ public Builder setMinSdkVersionForFine( int minSdkVersionForFine) { @@ -144,6 +159,17 @@ public final class LocationAccessPolicy { } /** + * If both the argument to {@link #setMinSdkVersionForFine} and + * {@link #setMinSdkVersionForCoarse} are greater than {@link Build.VERSION_CODES#BASE}, + * this method must be called with the min of the two to + * affirm that you do not want any location checks below a certain SDK version. + */ + public Builder setMinSdkVersionForEnforcement(int minSdkVersionForEnforcement) { + mMinSdkVersionForEnforcement = minSdkVersionForEnforcement; + return this; + } + + /** * Optional, for logging purposes only. */ public Builder setMethod(String method) { @@ -161,6 +187,26 @@ public final class LocationAccessPolicy { /** build LocationPermissionQuery */ public LocationPermissionQuery build() { + if (mMinSdkVersionForCoarse < 0 || mMinSdkVersionForFine < 0) { + throw new IllegalArgumentException("Must specify min sdk versions for" + + " enforcement for both coarse and fine permissions"); + } + if (mMinSdkVersionForFine > Build.VERSION_CODES.BASE + && mMinSdkVersionForCoarse > Build.VERSION_CODES.BASE) { + if (mMinSdkVersionForEnforcement != Math.min( + mMinSdkVersionForCoarse, mMinSdkVersionForFine)) { + throw new IllegalArgumentException("setMinSdkVersionForEnforcement must be" + + " called."); + } + } + + if (mMinSdkVersionForFine < mMinSdkVersionForCoarse) { + throw new IllegalArgumentException("Since fine location permission includes" + + " access to coarse location, the min sdk level for enforcement of" + + " the fine location permission must not be less than the min sdk" + + " level for enforcement of the coarse location permission."); + } + return new LocationPermissionQuery(mCallingPackage, mCallingFeatureId, mCallingUid, mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine, mLogAsInfo, mMethod); diff --git a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java index 0b47547d3b0c..e9b7d95b170a 100644 --- a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java +++ b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.telephony; +package com.android.internal.telephony; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java index 179248dd2cf9..804d1ed57eb6 100644 --- a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java +++ b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.net.Uri; +import android.util.ArraySet; import android.util.Log; import android.util.Pair; @@ -24,6 +25,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * Utility methods for parsing parts of {@link android.telephony.ims.SipMessage}s. @@ -70,6 +73,24 @@ public class SipMessageParsingUtils { // compact form of the call-id header key private static final String CALL_ID_SIP_HEADER_KEY_COMPACT = "i"; + // from header key + private static final String FROM_HEADER_KEY = "from"; + // compact form of the from header key + private static final String FROM_HEADER_KEY_COMPACT = "f"; + + // to header key + private static final String TO_HEADER_KEY = "to"; + // compact form of the to header key + private static final String TO_HEADER_KEY_COMPACT = "t"; + + // The tag parameter found in both the from and to headers + private static final String TAG_PARAM_KEY = "tag"; + + // accept-contact header key + private static final String ACCEPT_CONTACT_HEADER_KEY = "accept-contact"; + // compact form of the accept-contact header key + private static final String ACCEPT_CONTACT_HEADER_KEY_COMPACT = "a"; + /** * @return true if the SIP message start line is considered a request (based on known request * methods). @@ -81,6 +102,15 @@ public class SipMessageParsingUtils { } /** + * @return true if the SIP message start line is considered a response. + */ + public static boolean isSipResponse(String startLine) { + String[] splitLine = splitStartLineAndVerify(startLine); + if (splitLine == null) return false; + return verifySipResponse(splitLine); + } + + /** * Return the via branch parameter, which is used to identify the transaction ID (request and * response pair) in a SIP transaction. * @param headerString The string containing the headers of the SIP message. @@ -95,35 +125,42 @@ public class SipMessageParsingUtils { // branch param YY1. String[] subHeaders = header.second.split(SUBHEADER_VALUE_SEPARATOR); for (String subHeader : subHeaders) { - // Search for ;branch=z9hG4bKXXXXXX and return parameter value - String[] params = subHeader.split(PARAM_SEPARATOR); - if (params.length < 2) { - // This param doesn't include a branch param, move to next param. - Log.w(TAG, "getTransactionId: via detected without branch param:" - + subHeader); - continue; - } - // by spec, each param can only appear once in a header. - for (String param : params) { - String[] pair = param.split(PARAM_KEY_VALUE_SEPARATOR); - if (pair.length < 2) { - // ignore info before the first parameter - continue; - } - if (pair.length > 2) { - Log.w(TAG, - "getTransactionId: unexpected parameter" + Arrays.toString(pair)); - } - // Trim whitespace in parameter - pair[0] = pair[0].trim(); - pair[1] = pair[1].trim(); - if (BRANCH_PARAM_KEY.equalsIgnoreCase(pair[0])) { - // There can be multiple "Via" headers in the SIP message, however we want - // to return the first once found, as this corresponds with the transaction - // that is relevant here. - return pair[1]; - } - } + String paramValue = getParameterValue(subHeader, BRANCH_PARAM_KEY); + if (paramValue == null) continue; + return paramValue; + } + } + return null; + } + + /** + * Search a header's value for a specific parameter. + * @param headerValue The header key's value. + * @param parameterKey The parameter key we are looking for. + * @return The value associated with the specified parameter key or {@link null} if that key is + * not found. + */ + private static String getParameterValue(String headerValue, String parameterKey) { + String[] params = headerValue.split(PARAM_SEPARATOR); + if (params.length < 2) { + return null; + } + // by spec, each param can only appear once in a header. + for (String param : params) { + String[] pair = param.split(PARAM_KEY_VALUE_SEPARATOR); + if (pair.length < 2) { + // ignore info before the first parameter + continue; + } + if (pair.length > 2) { + Log.w(TAG, + "getParameterValue: unexpected parameter" + Arrays.toString(pair)); + } + // Trim whitespace in parameter + pair[0] = pair[0].trim(); + pair[1] = pair[1].trim(); + if (parameterKey.equalsIgnoreCase(pair[0])) { + return pair[1]; } } return null; @@ -134,18 +171,105 @@ public class SipMessageParsingUtils { * @param headerString The string containing the headers of the SIP message. */ public static String getCallId(String headerString) { - // search for the call-Id header, there should only be one in the header. + // search for the call-Id header, there should only be one in the headers. List<Pair<String, String>> headers = parseHeaders(headerString, true, CALL_ID_SIP_HEADER_KEY, CALL_ID_SIP_HEADER_KEY_COMPACT); return !headers.isEmpty() ? headers.get(0).second : null; } - private static String[] splitStartLineAndVerify(String startLine) { - String[] splitLine = startLine.split(" "); + /** + * @return Return the from header's tag parameter or {@code null} if it doesn't exist. + */ + public static String getFromTag(String headerString) { + // search for the from header, there should only be one in the headers. + List<Pair<String, String>> headers = parseHeaders(headerString, true, + FROM_HEADER_KEY, FROM_HEADER_KEY_COMPACT); + if (headers.isEmpty()) { + return null; + } + // There should only be one from header in the SIP message + return getParameterValue(headers.get(0).second, TAG_PARAM_KEY); + } + + /** + * @return Return the to header's tag parameter or {@code null} if it doesn't exist. + */ + public static String getToTag(String headerString) { + // search for the to header, there should only be one in the headers. + List<Pair<String, String>> headers = parseHeaders(headerString, true, + TO_HEADER_KEY, TO_HEADER_KEY_COMPACT); + if (headers.isEmpty()) { + return null; + } + // There should only be one from header in the SIP message + return getParameterValue(headers.get(0).second, TAG_PARAM_KEY); + } + + /** + * Validate that the start line is correct and split into its three segments. + * @param startLine The start line to verify and split. + * @return The split start line, which will always have three segments. + */ + public static String[] splitStartLineAndVerify(String startLine) { + String[] splitLine = startLine.split(" ", 3); if (isStartLineMalformed(splitLine)) return null; return splitLine; } + + /** + * @return All feature tags starting with "+" in the Accept-Contact header. + */ + public static Set<String> getAcceptContactFeatureTags(String headerString) { + List<Pair<String, String>> headers = SipMessageParsingUtils.parseHeaders(headerString, + false, ACCEPT_CONTACT_HEADER_KEY, ACCEPT_CONTACT_HEADER_KEY_COMPACT); + if (headerString.isEmpty()) { + return Collections.emptySet(); + } + Set<String> featureTags = new ArraySet<>(); + for (Pair<String, String> header : headers) { + String[] splitParams = header.second.split(PARAM_SEPARATOR); + if (splitParams.length < 2) { + continue; + } + // Start at 1 here, since the first entry is the header value and not params. + // We only care about IMS feature tags here, so filter tags with a "+" + Set<String> fts = Arrays.asList(splitParams).subList(1, splitParams.length).stream() + .map(String::trim).filter(p -> p.startsWith("+")).collect(Collectors.toSet()); + for (String ft : fts) { + String[] paramKeyValue = ft.split(PARAM_KEY_VALUE_SEPARATOR, 2); + if (paramKeyValue.length < 2) { + featureTags.add(ft); + continue; + } + // Splits keys like +a="b,c" into +a="b" and +a="c" + String[] splitValue = splitParamValue(paramKeyValue[1]); + for (String value : splitValue) { + featureTags.add(paramKeyValue[0] + PARAM_KEY_VALUE_SEPARATOR + value); + } + } + } + return featureTags; + } + + /** + * Takes a string such as "\"a,b,c,d\"" and splits it by "," into a String array of + * [\"a\", \"b\", \"c\", \"d\"] + */ + private static String[] splitParamValue(String paramValue) { + if (!paramValue.startsWith("\"") && !paramValue.endsWith("\"")) { + return new String[] {paramValue}; + } + // Remove quotes on outside + paramValue = paramValue.substring(1, paramValue.length() - 1); + String[] splitValues = paramValue.split(","); + for (int i = 0; i < splitValues.length; i++) { + // Encapsulate each split value in its own quotations. + splitValues[i] = "\"" + splitValues[i] + "\""; + } + return splitValues; + } + private static boolean isStartLineMalformed(String[] startLine) { if (startLine == null || startLine.length == 0) { return true; @@ -158,18 +282,27 @@ public class SipMessageParsingUtils { private static boolean verifySipRequest(String[] request) { // Request-Line = Method SP Request-URI SP SIP-Version CRLF - boolean verified = request[2].contains(SIP_VERSION_2); - verified &= (Uri.parse(request[1]).getScheme() != null); + if (!request[2].contains(SIP_VERSION_2)) return false; + boolean verified; + try { + verified = (Uri.parse(request[1]).getScheme() != null); + } catch (NumberFormatException e) { + return false; + } verified &= Arrays.stream(SIP_REQUEST_METHODS).anyMatch(s -> request[0].contains(s)); return verified; } private static boolean verifySipResponse(String[] response) { // Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF - boolean verified = response[0].contains(SIP_VERSION_2); - int statusCode = Integer.parseInt(response[1]); - verified &= (statusCode >= 100 && statusCode < 700); - return verified; + if (!response[0].contains(SIP_VERSION_2)) return false; + int statusCode; + try { + statusCode = Integer.parseInt(response[1]); + } catch (NumberFormatException e) { + return false; + } + return (statusCode >= 100 && statusCode < 700); } /** @@ -184,7 +317,7 @@ public class SipMessageParsingUtils { * (This is internally an equalsIgnoreMatch comparison). * @return the matched header keys and values. */ - private static List<Pair<String, String>> parseHeaders(String headerString, + public static List<Pair<String, String>> parseHeaders(String headerString, boolean stopAtFirstMatch, String... matchingHeaderKeys) { // Ensure there is no leading whitespace headerString = removeLeadingWhitespace(headerString); diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java index b8b60da019af..16614c87e7c2 100644 --- a/telephony/common/com/android/internal/telephony/SmsApplication.java +++ b/telephony/common/com/android/internal/telephony/SmsApplication.java @@ -40,7 +40,6 @@ import android.os.Process; import android.os.UserHandle; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; -import android.telephony.PackageChangeReceiver; import android.telephony.TelephonyManager; import android.util.Log; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 210e4a5e17ca..f6ba7becc922 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4106,6 +4106,26 @@ public class CarrierConfigManager { public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY = KEY_PREFIX + "rcs_feature_tag_allowed_string_array"; + /** + * Flag indicating whether or not carrier forbids device send the RCS request when the + * device receive the network response with the SIP code 489 BAD EVENT. + * <p> + * The default value for this key is {@code false}. + * @hide + */ + public static final String KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL = + KEY_PREFIX + "rcs_request_forbidden_by_sip_489_bool"; + + /** + * Indicates the interval that SUBSCRIBE requests from applications will be retried at when + * the carrier network has responded to a previous request with a forbidden error. + * <p> + * The default value for this key is 20 minutes. + * @hide + */ + public static final String KEY_RCS_REQUEST_RETRY_INTERVAL_MILLIS_LONG = + KEY_PREFIX + "rcs_request_retry_interval_millis_long"; + private Ims() {} private static PersistableBundle getDefaults() { @@ -4119,6 +4139,8 @@ public class CarrierConfigManager { defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false); defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true); defaults.putInt(KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT, 30 * 24 * 60 * 60); + defaults.putBoolean(KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL, false); + defaults.putLong(KEY_RCS_REQUEST_RETRY_INTERVAL_MILLIS_LONG, 20 * 60 * 1000); defaults.putStringArray(KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY, new String[]{ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg\"", "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg\"", @@ -4367,6 +4389,14 @@ public class CarrierConfigManager { public static final String KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL = "display_no_data_notification_on_permanent_failure_bool"; + /** + * Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes + * + * @hide + */ + public static final String KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL = + "unthrottle_data_retry_when_tac_changes_bool"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -4934,6 +4964,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, true); sDefaults.putBoolean(KEY_HIDE_ENABLE_2G, false); sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false); + sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false); } /** diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java index 0dfc7f6df27d..b3ec1f0415e4 100644 --- a/telephony/java/android/telephony/CellIdentityNr.java +++ b/telephony/java/android/telephony/CellIdentityNr.java @@ -231,7 +231,7 @@ public final class CellIdentityNr extends CellIdentity { } /** - * @return Mobile Network Code in string fomrat, or {@code null} if unknown. + * @return Mobile Network Code in string format, or {@code null} if unknown. */ @Nullable public String getMncString() { diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index 1c9cd94b245d..8a4bb4642887 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -182,16 +182,6 @@ public final class PhysicalChannelConfig implements Parcelable { } /** - * @return the absolute radio frequency channel number for this physical channel, - * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown. - * @deprecated Use {@link #getDownlinkChannelNumber()} to get the channel number. - */ - @Deprecated - public int getChannelNumber() { - return getDownlinkChannelNumber(); - } - - /** * @return the rough frequency range for this physical channel, * {@link ServiceState#FREQUENCY_RANGE_UNKNOWN} if unknown. * @see {@link ServiceState#FREQUENCY_RANGE_LOW} diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 2908e94aad81..06a2648f3bf6 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -47,6 +47,7 @@ import android.net.NetworkPolicyManager; import android.net.Uri; import android.os.Binder; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.ParcelUuid; @@ -55,6 +56,7 @@ import android.os.RemoteException; import android.provider.Telephony.SimInfo; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsMmTelManager; +import android.util.Base64; import android.util.Log; import android.util.Pair; @@ -66,6 +68,11 @@ import com.android.internal.util.FunctionalUtils; import com.android.internal.util.Preconditions; import com.android.telephony.Rlog; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -150,6 +157,22 @@ public class SubscriptionManager { public static final String CACHE_KEY_SLOT_INDEX_PROPERTY = "cache_key.telephony.get_slot_index"; + /** @hide */ + public static final String GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME = "getSimSpecificSettings"; + + /** @hide */ + public static final String RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME = + "restoreSimSpecificSettings"; + + /** + * Key to the backup & restore data byte array in the Bundle that is returned by {@link + * #getAllSimSpecificSettingsForBackup()} or to be pass in to {@link + * #restoreAllSimSpecificSettings()}. + * + * @hide + */ + public static final String KEY_SIM_SPECIFIC_SETTINGS_DATA = "KEY_SIM_SPECIFIC_SETTINGS_DATA"; + private static final int MAX_CACHE_SIZE = 4; private static class VoidPropertyInvalidatedCache<T> @@ -372,6 +395,28 @@ public class SubscriptionManager { public static final Uri WFC_ROAMING_ENABLED_CONTENT_URI = Uri.withAppendedPath( CONTENT_URI, "wfc_roaming_enabled"); + + /** + * A content {@link uri} used to call the appropriate backup or restore method for sim-specific + * settings + * <p> + * See {@link #GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME} and {@link + * #RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME} for information on what method to call. + * @hide + */ + @NonNull + public static final Uri SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI = Uri.withAppendedPath( + CONTENT_URI, "backup_and_restore"); + + /** + * A content {@link uri} used to notify contentobservers listening to siminfo restore during + * SuW. + * @hide + */ + @NonNull + public static final Uri SIM_INFO_SUW_RESTORE_CONTENT_URI = Uri.withAppendedPath( + SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, "suw_restore"); + /** * TelephonyProvider unique key column name is the subscription id. * <P>Type: TEXT (String)</P> @@ -543,6 +588,50 @@ public class SubscriptionManager { public @interface SimDisplayNameSource {} /** + * Device status is not shared to a remote party. + */ + public static final int D2D_SHARING_DISABLED = 0; + + /** + * Device status is shared with all numbers in the user's contacts. + */ + public static final int D2D_SHARING_ALL_CONTACTS = 1; + + /** + * Device status is shared with all selected contacts. + */ + public static final int D2D_SHARING_SELECTED_CONTACTS = 2; + + /** + * Device status is shared whenever possible. + */ + public static final int D2D_SHARING_ALL = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"D2D_SHARING_"}, + value = { + D2D_SHARING_DISABLED, + D2D_SHARING_ALL_CONTACTS, + D2D_SHARING_SELECTED_CONTACTS, + D2D_SHARING_ALL + }) + public @interface DeviceToDeviceStatusSharing {} + + /** + * TelephonyProvider column name for device to device sharing status. + * <P>Type: INTEGER (int)</P> + */ + public static final String D2D_STATUS_SHARING = SimInfo.COLUMN_D2D_STATUS_SHARING; + + /** + * TelephonyProvider column name for contacts information that allow device to device sharing. + * <P>Type: TEXT (String)</P> + */ + public static final String D2D_STATUS_SHARING_SELECTED_CONTACTS = + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS; + + /** * TelephonyProvider column name for the color of a SIM. * <P>Type: INTEGER (int)</P> */ @@ -832,6 +921,14 @@ public class SubscriptionManager { public static final String PROFILE_CLASS = SimInfo.COLUMN_PROFILE_CLASS; /** + * TelephonyProvider column name for VoIMS opt-in status. + * + * <P>Type: INTEGER (int)</P> + * @hide + */ + public static final String VOIMS_OPT_IN_STATUS = SimInfo.COLUMN_VOIMS_OPT_IN_STATUS; + + /** * Profile class of the subscription * @hide */ @@ -2335,6 +2432,57 @@ public class SubscriptionManager { } /** + * Serialize list of contacts uri to string + * @hide + */ + public static String serializeUriLists(List<Uri> uris) { + List<String> contacts = new ArrayList<>(); + for (Uri uri : uris) { + contacts.add(uri.toString()); + } + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(contacts); + oos.flush(); + return Base64.encodeToString(bos.toByteArray(), Base64.DEFAULT); + } catch (IOException e) { + logd("serializeUriLists IO exception"); + } + return ""; + } + + /** + * Return list of contacts uri corresponding to query result. + * @param subId Subscription Id of Subscription + * @param propKey Column name in SubscriptionInfo database + * @return list of contacts uri to be returned + * @hide + */ + private static List<Uri> getContactsFromSubscriptionProperty(int subId, String propKey, + Context context) { + String result = getSubscriptionProperty(subId, propKey, context); + if (result != null) { + try { + byte[] b = Base64.decode(result, Base64.DEFAULT); + ByteArrayInputStream bis = new ByteArrayInputStream(b); + ObjectInputStream ois = new ObjectInputStream(bis); + List<String> contacts = ArrayList.class.cast(ois.readObject()); + List<Uri> uris = new ArrayList<>(); + for (String contact : contacts) { + uris.add(Uri.parse(contact)); + } + return uris; + } catch (IOException e) { + logd("getContactsFromSubscriptionProperty IO exception"); + } catch (ClassNotFoundException e) { + logd("getContactsFromSubscriptionProperty ClassNotFound exception"); + } + } + return new ArrayList<>(); + } + + /** * Store properties associated with SubscriptionInfo in database * @param subId Subscription Id of Subscription * @param propKey Column name in SubscriptionInfo database @@ -3318,6 +3466,70 @@ public class SubscriptionManager { } /** + * Set the device to device status sharing user preference for a subscription ID. The setting + * app uses this method to indicate with whom they wish to share device to device status + * information. + * @param sharing the status sharing preference + * @param subId the unique Subscription ID in database + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setDeviceToDeviceStatusSharing(@DeviceToDeviceStatusSharing int sharing, + int subId) { + if (VDBG) { + logd("[setDeviceToDeviceStatusSharing] + sharing: " + sharing + " subId: " + subId); + } + setSubscriptionPropertyHelper(subId, "setDeviceToDeviceSharingStatus", + (iSub)->iSub.setDeviceToDeviceStatusSharing(sharing, subId)); + } + + /** + * Returns the user-chosen device to device status sharing preference + * @param subId Subscription id of subscription + * @return The device to device status sharing preference + */ + public @DeviceToDeviceStatusSharing int getDeviceToDeviceStatusSharing(int subId) { + if (VDBG) { + logd("[getDeviceToDeviceStatusSharing] + subId: " + subId); + } + return getIntegerSubscriptionProperty(subId, D2D_STATUS_SHARING, D2D_SHARING_DISABLED, + mContext); + } + + /** + * Set the list of contacts that allow device to device status sharing for a subscription ID. + * The setting app uses this method to indicate with whom they wish to share device to device + * status information. + * @param contacts The list of contacts that allow device to device status sharing + * @param subscriptionId The unique Subscription ID in database + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setDeviceToDeviceStatusSharingContacts(@NonNull List<Uri> contacts, + int subscriptionId) { + String contactString = serializeUriLists(contacts); + if (VDBG) { + logd("[setDeviceToDeviceStatusSharingContacts] + contacts: " + contactString + + " subId: " + subscriptionId); + } + setSubscriptionPropertyHelper(subscriptionId, "setDeviceToDeviceSharingStatus", + (iSub)->iSub.setDeviceToDeviceStatusSharingContacts(serializeUriLists(contacts), + subscriptionId)); + } + + /** + * Returns the list of contacts that allow device to device status sharing. + * @param subscriptionId Subscription id of subscription + * @return The list of contacts that allow device to device status sharing + */ + public @NonNull List<Uri> getDeviceToDeviceStatusSharingContacts( + int subscriptionId) { + if (VDBG) { + logd("[getDeviceToDeviceStatusSharingContacts] + subId: " + subscriptionId); + } + return getContactsFromSubscriptionProperty(subscriptionId, + D2D_STATUS_SHARING_SELECTED_CONTACTS, mContext); + } + + /** * DO NOT USE. * This API is designed for features that are not finished at this point. Do not call this API. * @hide @@ -3446,4 +3658,71 @@ public class SubscriptionManager { sSlotIndexCache.clear(); sPhoneIdCache.clear(); } + + /** + * Called to retrieve SIM-specific settings data to be backed up. + * + * @return data in byte[] to be backed up. + * + * @hide + */ + @NonNull + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public byte[] getAllSimSpecificSettingsForBackup() { + Bundle bundle = mContext.getContentResolver().call( + SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, + GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME, null, null); + return bundle.getByteArray(SubscriptionManager.KEY_SIM_SPECIFIC_SETTINGS_DATA); + } + + /** + * Called to attempt to restore the backed up sim-specific configs to device for specific sim. + * This will try to restore the data that was stored internally when {@link + * #restoreAllSimSpecificSettingsFromBackup(byte[] data)} was called during setup wizard. + * End result is SimInfoDB is modified to match any backed up configs for the requested + * inserted sim. + * + * <p> + * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any SimInfoDB + * entry is updated as the result of this method call. + * + * @param iccId of the sim that a restore is requested for. + * + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void restoreSimSpecificSettingsForIccIdFromBackup(@NonNull String iccId) { + mContext.getContentResolver().call( + SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, + RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, + iccId, null); + } + + /** + * Called during setup wizard restore flow to attempt to restore the backed up sim-specific + * configs to device for all existing SIMs in SimInfoDB. Internally, it will store the backup + * data in an internal file. This file will persist on device for device's lifetime and will be + * used later on when a SIM is inserted to restore that specific SIM's settings by calling + * {@link #restoreSimSpecificSettingsForIccIdFromBackup(String iccId)}. End result is + * SimInfoDB is modified to match any backed up configs for the appropriate inserted SIMs. + * + * <p> + * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any SimInfoDB + * entry is updated as the result of this method call. + * + * @param data with the sim specific configs to be backed up. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void restoreAllSimSpecificSettingsFromBackup(@NonNull byte[] data) { + Bundle bundle = new Bundle(); + bundle.putByteArray(KEY_SIM_SPECIFIC_SETTINGS_DATA, data); + mContext.getContentResolver().call( + SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, + RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, + null, bundle); + } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 1cfb1d43eacc..ae6a3e846950 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -11205,26 +11205,26 @@ public class TelephonyManager { } /** - * Return a list of certs in hex string from loaded carrier privileges access rules. + * Return a list of certs as hex strings from loaded carrier privileges access rules. * - * @return a list of certificate in hex string. return {@code null} if there is no certs - * or privilege rules are not loaded yet. - * - * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} + * @return a list of certificates as hex strings, or an empty list if there are no certs or + * privilege rules are not loaded yet. * @hide */ + @TestApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @NonNull public List<String> getCertsFromCarrierPrivilegeAccessRules() { + List<String> certs = null; try { ITelephony service = getITelephony(); if (service != null) { - return service.getCertsFromCarrierPrivilegeAccessRules(getSubId()); + certs = service.getCertsFromCarrierPrivilegeAccessRules(getSubId()); } } catch (RemoteException ex) { // This could happen if binder process crashes. } - return null; + return certs == null ? Collections.emptyList() : certs; } /** diff --git a/telephony/java/android/telephony/ims/DelegateMessageCallback.java b/telephony/java/android/telephony/ims/DelegateMessageCallback.java index 0d82a54a0f32..a008cfdbc535 100644 --- a/telephony/java/android/telephony/ims/DelegateMessageCallback.java +++ b/telephony/java/android/telephony/ims/DelegateMessageCallback.java @@ -35,12 +35,12 @@ import android.telephony.ims.stub.SipDelegate; public interface DelegateMessageCallback { /** - * Send a new incoming SIP message to the remote application for processing. + * Sends a new incoming SIP message to the remote application for processing. */ void onMessageReceived(@NonNull SipMessage message); /** - * Notify the remote application that a previous request to send a SIP message using + * Notifies the remote application that a previous request to send a SIP message using * {@link SipDelegate#sendMessage} has succeeded. * * @param viaTransactionId The transaction ID found in the via header field of the @@ -49,7 +49,7 @@ public interface DelegateMessageCallback { void onMessageSent(@NonNull String viaTransactionId); /** - * Notify the remote application that a previous request to send a SIP message using + * Notifies the remote application that a previous request to send a SIP message using * {@link SipDelegate#sendMessage} has failed. * * @param viaTransactionId The Transaction ID found in the via header field of the previously diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index d1a893f61e00..740332708dbc 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -713,15 +713,8 @@ public class ImsMmTelManager implements RegistrationManager { * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VT_AVAILABLE_BOOL * @see android.telephony.CarrierConfigManager#KEY_CARRIER_IMS_GBA_REQUIRED_BOOL * @see #isAvailable(int, int) - * - * @param imsRegTech The IMS registration technology, can be one of the following: - * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE}, - * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} - * @param capability The IMS MmTel capability to query, can be one of the following: - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS} + * @param imsRegTech The IMS registration technology. + * @param capability The IMS MmTel capability to query. * @return {@code true} if the MmTel IMS capability is capable for this subscription, false * otherwise. * @hide @@ -748,14 +741,8 @@ public class ImsMmTelManager implements RegistrationManager { * * @see #isCapable(int, int) * - * @param imsRegTech The IMS registration technology, can be one of the following: - * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE}, - * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} - * @param capability The IMS MmTel capability to query, can be one of the following: - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS} + * @param imsRegTech The IMS registration technology. + * @param capability The IMS MmTel capability to query. * @return {@code true} if the MmTel IMS capability is available for this subscription, false * otherwise. * @hide diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 1e80ab7a405c..c420f35bc6cd 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -866,6 +866,19 @@ public class ProvisioningManager { public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; /** + * An integer key representing the voice over IMS opt-in provisioning status for the + * associated subscription. Determines whether the user can see for voice services over + * IMS. + * <p> + * Use {@link #PROVISIONING_VALUE_ENABLED} to enable VoIMS provisioning and + * {@link #PROVISIONING_VALUE_DISABLED} to disable VoIMS provisioning. + * @see #setProvisioningIntValue(int, int) + * @see #getProvisioningIntValue(int) + * @hide + */ + public static final int KEY_VOIMS_OPT_IN_STATUS = 68; + + /** * Callback for IMS provisioning changes. */ public static class Callback { diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java index 8a3121118fde..6867c866cd94 100644 --- a/telephony/java/android/telephony/ims/RcsConfig.java +++ b/telephony/java/android/telephony/ims/RcsConfig.java @@ -22,10 +22,10 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; import android.provider.Telephony.SimInfo; import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; import com.android.telephony.Rlog; @@ -36,7 +36,9 @@ import org.xmlpull.v1.XmlPullParserFactory; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -44,23 +46,138 @@ import java.util.zip.GZIPOutputStream; * RCS config data and methods to process the config * @hide */ -public final class RcsConfig implements Parcelable { +public final class RcsConfig { private static final String LOG_TAG = "RcsConfig"; private static final boolean DBG = Build.IS_ENG; - // Tag for Rcs Volte single registration defined in RCC.07 A.1.6.2 - private static final String TAG_SINGLE_REGISTRATION = "rcsVolteSingleRegistration"; + // Tag and attribute defined in RCC.07 A.2 + private static final String TAG_CHARACTERISTIC = "characteristic"; + private static final String TAG_PARM = "parm"; + private static final String ATTRIBUTE_TYPE = "type"; + private static final String ATTRIBUTE_NAME = "name"; + private static final String ATTRIBUTE_VALUE = "value"; + // Keyword for Rcs Volte single registration defined in RCC.07 A.1.6.2 + private static final String PARM_SINGLE_REGISTRATION = "rcsVolteSingleRegistration"; - private final HashMap<String, String> mValues = new HashMap<>(); + /** + * Characteristic of the RCS provisioning config + */ + public static class Characteristic { + private String mType; + private final Map<String, String> mParms = new ArrayMap<>(); + private final Set<Characteristic> mSubs = new ArraySet<>(); + private final Characteristic mParent; + + private Characteristic(String type, Characteristic parent) { + mType = type; + mParent = parent; + } + + private String getType() { + return mType; + } + + private Map<String, String> getParms() { + return mParms; + } + + private Set<Characteristic> getSubs() { + return mSubs; + } + + private Characteristic getParent() { + return mParent; + } + + private Characteristic getSubByType(String type) { + if (TextUtils.equals(mType, type)) { + return this; + } + Characteristic result = null; + for (Characteristic sub : mSubs) { + result = sub.getSubByType(type); + if (result != null) { + break; + } + } + return result; + } + + private boolean hasSubByType(String type) { + return getSubByType(type) != null; + } - private RcsConfig(HashMap<String, String> values) { - mValues.putAll(values); + private String getParmValue(String name) { + String value = mParms.get(name); + if (value == null) { + for (Characteristic sub : mSubs) { + value = sub.getParmValue(name); + if (value != null) { + break; + } + } + } + return value; + } + + boolean hasParm(String name) { + if (mParms.containsKey(name)) { + return true; + } + + for (Characteristic sub : mSubs) { + if (sub.hasParm(name)) { + return true; + } + } + + return false; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("[" + mType + "]: "); + if (DBG) { + sb.append(mParms); + } + for (Characteristic sub : mSubs) { + sb.append("\n"); + sb.append(sub.toString().replace("\n", "\n\t")); + } + return sb.toString(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Characteristic)) { + return false; + } + + Characteristic o = (Characteristic) obj; + + return TextUtils.equals(mType, o.mType) && mParms.equals(o.mParms) + && mSubs.equals(o.mSubs); + } + + @Override + public int hashCode() { + return Objects.hash(mType, mParms, mSubs); + } } + private final Characteristic mRoot; + private Characteristic mCurrent; + private final byte[] mData; + public RcsConfig(byte[] data) throws IllegalArgumentException { if (data == null || data.length == 0) { throw new IllegalArgumentException("Empty data"); } + mRoot = new Characteristic(null, null); + mCurrent = mRoot; + mData = data; + Characteristic current = mRoot; ByteArrayInputStream inputStream = new ByteArrayInputStream(data); try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); @@ -69,16 +186,51 @@ public final class RcsConfig implements Parcelable { xpp.setInput(inputStream, null); int eventType = xpp.getEventType(); String tag = null; - while (eventType != XmlPullParser.END_DOCUMENT) { + while (eventType != XmlPullParser.END_DOCUMENT && current != null) { if (eventType == XmlPullParser.START_TAG) { - tag = xpp.getName().trim(); + tag = xpp.getName().trim().toLowerCase(); + if (TAG_CHARACTERISTIC.equals(tag)) { + int count = xpp.getAttributeCount(); + String type = null; + if (count > 0) { + for (int i = 0; i < count; i++) { + String name = xpp.getAttributeName(i).trim().toLowerCase(); + if (ATTRIBUTE_TYPE.equals(name)) { + type = xpp.getAttributeValue(xpp.getAttributeNamespace(i), + name).trim().toLowerCase(); + break; + } + } + } + Characteristic next = new Characteristic(type, current); + current.getSubs().add(next); + current = next; + } else if (TAG_PARM.equals(tag)) { + int count = xpp.getAttributeCount(); + String key = null; + String value = null; + if (count > 1) { + for (int i = 0; i < count; i++) { + String name = xpp.getAttributeName(i).trim().toLowerCase(); + if (ATTRIBUTE_NAME.equals(name)) { + key = xpp.getAttributeValue(xpp.getAttributeNamespace(i), + name).trim().toLowerCase(); + } else if (ATTRIBUTE_VALUE.equals(name)) { + value = xpp.getAttributeValue(xpp.getAttributeNamespace(i), + name).trim(); + } + } + } + if (key != null && value != null) { + current.getParms().put(key, value); + } + } } else if (eventType == XmlPullParser.END_TAG) { - tag = null; - } else if (eventType == XmlPullParser.TEXT) { - String value = xpp.getText().trim(); - if (!TextUtils.isEmpty(tag) && !TextUtils.isEmpty(value)) { - mValues.put(tag, value); + tag = xpp.getName().trim().toLowerCase(); + if (TAG_CHARACTERISTIC.equals(tag)) { + current = current.getParent(); } + tag = null; } eventType = xpp.next(); } @@ -102,7 +254,8 @@ public final class RcsConfig implements Parcelable { * @return Returns the config value if it exists, or defaultVal. */ public @Nullable String getString(@NonNull String tag, @Nullable String defaultVal) { - return mValues.containsKey(tag) ? mValues.get(tag) : defaultVal; + String value = mCurrent.getParmValue(tag.trim().toLowerCase()); + return value != null ? value : defaultVal; } /** @@ -115,7 +268,7 @@ public final class RcsConfig implements Parcelable { */ public int getInteger(@NonNull String tag, int defaultVal) { try { - return Integer.parseInt(mValues.get(tag)); + return Integer.parseInt(getString(tag, null)); } catch (NumberFormatException e) { logd("error to getInteger for " + tag + " due to " + e); } @@ -131,10 +284,8 @@ public final class RcsConfig implements Parcelable { * @return Returns the config value if it exists, or defaultVal. */ public boolean getBoolean(@NonNull String tag, boolean defaultVal) { - if (!mValues.containsKey(tag)) { - return defaultVal; - } - return Boolean.parseBoolean(mValues.get(tag)); + String value = getString(tag, null); + return value != null ? Boolean.parseBoolean(value) : defaultVal; } /** @@ -145,15 +296,70 @@ public final class RcsConfig implements Parcelable { * @return Returns true if it exists, or false. */ public boolean hasConfig(@NonNull String tag) { - return mValues.containsKey(tag); + return mCurrent.hasParm(tag.trim().toLowerCase()); + } + + /** + * Return the Characteristic with the given type + */ + public @Nullable Characteristic getCharacteristic(@NonNull String type) { + return mCurrent.getSubByType(type.trim().toLowerCase()); + } + + /** + * Check whether the Characteristic with the given type exists + */ + public boolean hasCharacteristic(@NonNull String type) { + return mCurrent.getSubByType(type.trim().toLowerCase()) != null; + } + + /** + * Set current Characteristic to given Characteristic + */ + public void setCurrentCharacteristic(@NonNull Characteristic current) { + if (current != null) { + mCurrent = current; + } + } + + /** + * Move current Characteristic to parent layer + */ + public boolean moveToParent() { + if (mCurrent.getParent() == null) { + return false; + } + mCurrent = mCurrent.getParent(); + return true; + } + + /** + * Move current Characteristic to the root + */ + public void moveToRoot() { + mCurrent = mRoot; + } + + /** + * Return root Characteristic + */ + public @NonNull Characteristic getRoot() { + return mRoot; + } + + /** + * Return current Characteristic + */ + public @NonNull Characteristic getCurrentCharacteristic() { + return mCurrent; } /** * Check whether Rcs Volte single registration is supported by the config. */ public boolean isRcsVolteSingleRegistrationSupported() { - return getBoolean(TAG_SINGLE_REGISTRATION, false) - || getInteger(TAG_SINGLE_REGISTRATION, 0) != 0; + return getBoolean(PARM_SINGLE_REGISTRATION, false) + || getInteger(PARM_SINGLE_REGISTRATION, 0) != 0; } @Override @@ -161,12 +367,10 @@ public final class RcsConfig implements Parcelable { final StringBuilder sb = new StringBuilder(); sb.append("[RCS Config]"); if (DBG) { - mValues.forEach((t, v) -> { - sb.append("\n"); - sb.append(t); - sb.append(" : "); - sb.append(v); - }); + sb.append("=== Root ===\n"); + sb.append(mRoot); + sb.append("=== Current ===\n"); + sb.append(mCurrent); } return sb.toString(); } @@ -179,12 +383,12 @@ public final class RcsConfig implements Parcelable { RcsConfig other = (RcsConfig) obj; - return mValues.equals(other.mValues); + return mRoot.equals(other.mRoot) && mCurrent.equals(other.mCurrent); } @Override public int hashCode() { - return mValues.hashCode(); + return Objects.hash(mRoot, mCurrent); } /** @@ -275,38 +479,6 @@ public final class RcsConfig implements Parcelable { return isCompressed ? data : decompressGzip(data); } - /** - * {@link Parcelable#writeToParcel} - */ - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeMap(mValues); - } - - /** - * {@link Parcelable.Creator} - * - */ - public static final @NonNull Parcelable.Creator<RcsConfig> - CREATOR = new Creator<RcsConfig>() { - @Override - public RcsConfig createFromParcel(Parcel in) { - HashMap<String, String> values = in.readHashMap(null); - return values == null ? null : new RcsConfig(values); - } - - @Override - public RcsConfig[] newArray(int size) { - return new RcsConfig[size]; - } - }; - - /** - * {@link Parcelable#describeContents} - */ - public int describeContents() { - return 0; - } - private static void logd(String msg) { Rlog.d(LOG_TAG, msg); } diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index c49121f4dc5d..4713b7660e3a 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -82,6 +82,8 @@ public interface RegistrationManager { AccessNetworkConstants.TRANSPORT_TYPE_INVALID); put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + put(ImsRegistrationImplBase.REGISTRATION_TECH_NR, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); }}; diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java index ffbfde65e2d3..08513c23291a 100644 --- a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java +++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java @@ -26,6 +26,7 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import android.text.TextUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -561,7 +562,12 @@ public final class SipDelegateImsConfiguration implements Parcelable { builder.setSipCniHeader(getString(KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING)); builder.setSipAssociatedUriHeader(getString(KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING)); if (getBoolean(KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, false)) { - builder.setPublicGruuUri(Uri.parse(getString(KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING))); + String uri = getString(KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING); + Uri gruuUri = null; + if (!TextUtils.isEmpty(uri)) { + gruuUri = Uri.parse(uri); + } + builder.setPublicGruuUri(gruuUri); } if (getBoolean(KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL, false)) { builder.setIpSecConfiguration(new SipDelegateConfiguration.IpSecConfiguration( diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java index ee7302a753cc..97be45ae1c48 100644 --- a/telephony/java/android/telephony/ims/SipDelegateManager.java +++ b/telephony/java/android/telephony/ims/SipDelegateManager.java @@ -33,6 +33,7 @@ import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper; import android.telephony.ims.stub.DelegateConnectionMessageCallback; import android.telephony.ims.stub.DelegateConnectionStateCallback; import android.telephony.ims.stub.SipDelegate; +import android.util.ArrayMap; import com.android.internal.annotations.VisibleForTesting; @@ -79,13 +80,18 @@ public class SipDelegateManager { public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2; /** - * The SIP message has an invalid start line and the message can not be sent. + * The SIP message has an invalid start line and the message can not be sent or the start line + * failed validation due to the request containing a restricted SIP request method. + * {@link SipDelegateConnection}s can not send SIP requests for the methods: REGISTER, PUBLISH, + * or OPTIONS. */ public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3; /** * One or more of the header fields in the header section of the outgoing SIP message is invalid - * and the SIP message can not be sent. + * or contains a restricted header value and the SIP message can not be sent. + * {@link SipDelegateConnection}s can not send SIP SUBSCRIBE requests for the "Event" header + * value of "presence". */ public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4; @@ -96,7 +102,7 @@ public class SipDelegateManager { /** * The feature tag associated with the outgoing message does not match any known feature tags - * and this message can not be sent. + * or it matches a denied tag and this message can not be sent. */ public static final int MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG = 6; @@ -162,6 +168,35 @@ public class SipDelegateManager { }) public @interface MessageFailureReason {} + /**@hide*/ + public static final ArrayMap<Integer, String> MESSAGE_FAILURE_REASON_STRING_MAP = + new ArrayMap<>(11); + static { + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_UNKNOWN, + "MESSAGE_FAILURE_REASON_UNKNOWN"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_DEAD, + "MESSAGE_FAILURE_REASON_DELEGATE_DEAD"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_CLOSED, + "MESSAGE_FAILURE_REASON_DELEGATE_CLOSED"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS, + "MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT, + "MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG, + "MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG"); + MESSAGE_FAILURE_REASON_STRING_MAP.append( + MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE, + "MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE, + "MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NOT_REGISTERED, + "MESSAGE_FAILURE_REASON_NOT_REGISTERED"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION, + "MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION"); + MESSAGE_FAILURE_REASON_STRING_MAP.append( + MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION, + "MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION"); + } /** * Access to use this feature tag has been denied for an unknown reason. diff --git a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl index 5eee3890f1dc..1b5e5603ec66 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl @@ -47,4 +47,6 @@ interface IImsConfig { void removeRcsConfigCallback(IRcsConfigCallback c); void triggerRcsReconfiguration(); void setRcsClientConfiguration(in RcsClientConfiguration rcc); + void notifyIntImsConfigChanged(int item, int value); + void notifyStringImsConfigChanged(int item, String value); } diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index ddd6fbe38cf4..18cc37d7fbda 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -398,16 +398,6 @@ public class RcsFeature extends ImsFeature { /** * Remove the given CapabilityExchangeImplBase instance. - * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be removed. - * @hide - */ - public void removeCapabilityExchangeImpl( - @NonNull RcsCapabilityExchangeImplBase capExchangeImpl) { - // Override to implement the process of removing RcsCapabilityExchangeImplBase instance. - } - - /** - * Remove the given CapabilityExchangeImplBase instance. * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be destroyed. */ public void destroyCapabilityExchangeImpl( @@ -450,7 +440,7 @@ public class RcsFeature extends ImsFeature { // Remove the RcsCapabilityExchangeImplBase instance when the capability exchange // instance has been removed in the framework. if (mCapabilityExchangeImpl != null) { - removeCapabilityExchangeImpl(mCapabilityExchangeImpl); + destroyCapabilityExchangeImpl(mCapabilityExchangeImpl); } mCapabilityExchangeImpl = null; } @@ -468,7 +458,7 @@ public class RcsFeature extends ImsFeature { synchronized (mLock) { // Remove the original instance if (mCapabilityExchangeImpl != null) { - removeCapabilityExchangeImpl(mCapabilityExchangeImpl); + destroyCapabilityExchangeImpl(mCapabilityExchangeImpl); } mCapabilityExchangeImpl = createCapabilityExchangeImpl(listener); } diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index 4dcb7f59f4a7..d75da9035124 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -258,6 +258,16 @@ public class ImsConfigImplBase { public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException { getImsConfigImpl().setRcsClientConfiguration(rcc); } + + @Override + public void notifyIntImsConfigChanged(int item, int value) throws RemoteException { + notifyImsConfigChanged(item, value); + } + + @Override + public void notifyStringImsConfigChanged(int item, String value) throws RemoteException { + notifyImsConfigChanged(item, value); + } } /** diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java index 23032f0c4d38..35324a3c7975 100644 --- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java @@ -56,7 +56,8 @@ public class ImsRegistrationImplBase { @IntDef(value = { REGISTRATION_TECH_NONE, REGISTRATION_TECH_LTE, - REGISTRATION_TECH_IWLAN + REGISTRATION_TECH_IWLAN, + REGISTRATION_TECH_NR }) @Retention(RetentionPolicy.SOURCE) public @interface ImsRegistrationTech {} @@ -65,13 +66,18 @@ public class ImsRegistrationImplBase { */ public static final int REGISTRATION_TECH_NONE = -1; /** - * IMS is registered to IMS via LTE. + * This ImsService is registered to IMS via LTE. */ public static final int REGISTRATION_TECH_LTE = 0; /** - * IMS is registered to IMS via IWLAN. + * This ImsService is registered to IMS via IWLAN. */ public static final int REGISTRATION_TECH_IWLAN = 1; + // REGISTRATION_TECH = 2 omitted purposefully. + /** + * This ImsService is registered to IMS via NR. + */ + public static final int REGISTRATION_TECH_NR = 3; // Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current // state. diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 571efcee0e15..6493772039e6 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -300,4 +300,8 @@ interface ISub { boolean canDisablePhysicalSubscription(); int setUiccApplicationsEnabled(boolean enabled, int subscriptionId); + + int setDeviceToDeviceStatusSharing(int sharing, int subId); + + int setDeviceToDeviceStatusSharingContacts(String contacts, int subscriptionId); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 97078c3dd76e..3c55b7c8dbd6 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2398,6 +2398,12 @@ interface ITelephony { String getLastUcePidfXmlShell(int subId); /** + * Remove UCE requests cannot be sent to the network status. + * Note: This is designed for a SHELL command only. + */ + boolean removeUceRequestDisallowedStatus(int subId); + + /** * Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the * specified thresholds. */ diff --git a/test-base/Android.bp b/test-base/Android.bp index 9bd639b63ae0..b58aa11597c2 100644 --- a/test-base/Android.bp +++ b/test-base/Android.bp @@ -32,7 +32,7 @@ package { java_sdk_library { name: "android.test.base", - srcs: ["src/**/*.java"], + srcs: [":android-test-base-sources"], errorprone: { javacflags: ["-Xep:DepAnn:ERROR"], @@ -66,7 +66,7 @@ java_library_static { name: "android.test.base_static", installable: false, - srcs: ["src/**/*.java"], + srcs: [":android-test-base-sources"], errorprone: { javacflags: ["-Xep:DepAnn:ERROR"], @@ -114,6 +114,12 @@ java_library_static { ], } +filegroup { + name: "android-test-base-sources", + srcs: ["src/**/*.java"], + path: "src", +} + // Make the current.txt available for use by the cts/tests/signature tests. // ======================================================================== filegroup { diff --git a/test-mock/Android.bp b/test-mock/Android.bp index a2447d71c3bd..107292c81ab4 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -29,7 +29,7 @@ java_sdk_library { name: "android.test.mock", srcs: [ - "src/**/*.java", + ":android-test-mock-sources", // Note: Below are NOT APIs of this library. We only take APIs under // the android.test.mock package. They however provide private APIs that // android.test.mock APIs references to. @@ -38,6 +38,7 @@ java_sdk_library { ], libs: [ "framework", + "framework-annotations-lib", "app-compat-annotations", "unsupportedappusage", ], @@ -60,3 +61,9 @@ filegroup { "api/current.txt", ], } + +filegroup { + name: "android-test-mock-sources", + srcs: ["src/**/*.java"], + path: "src", +} diff --git a/test-runner/Android.bp b/test-runner/Android.bp index fe007e39f717..c380ae3a243b 100644 --- a/test-runner/Android.bp +++ b/test-runner/Android.bp @@ -29,7 +29,7 @@ package { java_sdk_library { name: "android.test.runner", - srcs: ["src/**/*.java"], + srcs: [":android-test-runner-sources"], errorprone: { javacflags: ["-Xep:DepAnn:ERROR"], @@ -76,7 +76,7 @@ java_library { java_library_static { name: "repackaged.android.test.runner", - srcs: ["src/**/*.java"], + srcs: [":android-test-runner-sources"], exclude_srcs: [ "src/android/test/ActivityUnitTestCase.java", "src/android/test/ApplicationTestCase.java", @@ -108,3 +108,9 @@ filegroup { "api/current.txt", ], } + +filegroup { + name: "android-test-runner-sources", + srcs: ["src/**/*.java"], + path: "src", +} diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk index bfb5b076237a..dab83046c28f 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk @@ -89,4 +89,7 @@ LOCAL_JAVA_RESOURCE_FILES := \ $(dynamiccodeloggertest_jar) \ $(dynamiccodeloggertest_executable) \ +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE include $(BUILD_PACKAGE) diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk index 9b155c930871..b6f34717658c 100644 --- a/tests/backup/Android.mk +++ b/tests/backup/Android.mk @@ -47,4 +47,7 @@ LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE include $(BUILD_PACKAGE) diff --git a/tests/vcn/OWNERS b/tests/vcn/OWNERS index 33b9f0f75f81..2441e772468c 100644 --- a/tests/vcn/OWNERS +++ b/tests/vcn/OWNERS @@ -3,5 +3,5 @@ set noparent benedictwong@google.com ckesting@google.com evitayan@google.com +junyin@google.com nharold@google.com -jchalard@google.com
\ No newline at end of file diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 0d3fd3fef49c..4ce78aa4d8c1 100644 --- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -16,13 +16,17 @@ package android.net.vcn; +import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.net.NetworkCapabilities; -import android.net.TunnelConnectionParams; +import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; +import android.net.vcn.persistablebundleutils.IkeSessionParamsUtilsTest; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest; import androidx.test.filters.SmallTest; @@ -60,7 +64,7 @@ public class VcnGatewayConnectionConfigTest { }; public static final int MAX_MTU = 1360; - public static final TunnelConnectionParams TUNNEL_CONNECTION_PARAMS = + public static final IkeTunnelConnectionParams TUNNEL_CONNECTION_PARAMS = TunnelConnectionParamsUtilsTest.buildTestParams(); public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-"; @@ -82,16 +86,12 @@ public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setRetryIntervalsMs(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); + newBuilder().setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); for (int caps : exposedCaps) { builder.addExposedCapability(caps); } - for (int caps : UNDERLYING_CAPS) { - builder.addRequiredUnderlyingCapability(caps); - } - return builder.build(); } @@ -120,11 +120,24 @@ public class VcnGatewayConnectionConfigTest { } @Test + public void testBuilderRequiresMobikeEnabled() { + try { + final IkeSessionParams ikeParams = + IkeSessionParamsUtilsTest.createBuilderMinimum() + .removeIkeOption(IKE_OPTION_MOBIKE) + .build(); + final IkeTunnelConnectionParams tunnelParams = + TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams); + new VcnGatewayConnectionConfig.Builder(GATEWAY_CONNECTION_NAME_PREFIX, tunnelParams); + fail("Expected exception due to MOBIKE not enabled"); + } catch (IllegalArgumentException e) { + } + } + + @Test public void testBuilderRequiresNonEmptyExposedCaps() { try { - newBuilder() - .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); + newBuilder().build(); fail("Expected exception due to invalid exposed capabilities"); } catch (IllegalArgumentException e) { @@ -134,7 +147,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonNullRetryInterval() { try { - newBuilder().setRetryIntervalsMs(null); + newBuilder().setRetryIntervalsMillis(null); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -143,7 +156,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonEmptyRetryInterval() { try { - newBuilder().setRetryIntervalsMs(new long[0]); + newBuilder().setRetryIntervalsMillis(new long[0]); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -168,13 +181,9 @@ public class VcnGatewayConnectionConfigTest { Arrays.sort(exposedCaps); assertArrayEquals(EXPOSED_CAPS, exposedCaps); - int[] underlyingCaps = config.getRequiredUnderlyingCapabilities(); - Arrays.sort(underlyingCaps); - assertArrayEquals(UNDERLYING_CAPS, underlyingCaps); - assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); - assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); + assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); assertEquals(MAX_MTU, config.getMaxMtu()); } diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java index 31561901be9e..abae81cf1742 100644 --- a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java +++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java @@ -16,13 +16,17 @@ package android.net.vcn; +import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; +import static android.net.NetworkCapabilities.REDACT_NONE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; +import android.os.Build; import android.os.Parcel; import org.junit.Test; @@ -51,6 +55,22 @@ public class VcnTransportInfoTest { } @Test + public void testMakeCopyRedactForAccessFineLocation() { + assertEquals( + SUB_ID, + ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION)) + .getSubId()); + + // TODO: remove the if statement when S pushes to AOSP. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + assertEquals( + WifiConfiguration.INVALID_NETWORK_ID, + ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy( + REDACT_FOR_ACCESS_FINE_LOCATION)).getWifiInfo().getNetworkId()); + } + } + + @Test public void testEquals() { assertEquals(CELL_UNDERLYING_INFO, CELL_UNDERLYING_INFO); assertEquals(WIFI_UNDERLYING_INFO, WIFI_UNDERLYING_INFO); @@ -58,14 +78,31 @@ public class VcnTransportInfoTest { } @Test - public void testParcelUnparcel() { - verifyParcelingIsNull(CELL_UNDERLYING_INFO); - verifyParcelingIsNull(WIFI_UNDERLYING_INFO); + public void testApplicableRedactions() { + assertEquals(REDACT_NONE, CELL_UNDERLYING_INFO.getApplicableRedactions()); + + final long wifiRedactions = WIFI_INFO.getApplicableRedactions(); + assertEquals(wifiRedactions, WIFI_UNDERLYING_INFO.getApplicableRedactions()); } - private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) { - Parcel parcel = Parcel.obtain(); - vcnTransportInfo.writeToParcel(parcel, 0 /* flags */); - assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel)); + @Test + public void testParcelNotRedactedForSysUi() { + VcnTransportInfo cellRedacted = parcelForSysUi(CELL_UNDERLYING_INFO); + assertEquals(SUB_ID, cellRedacted.getSubId()); + VcnTransportInfo wifiRedacted = parcelForSysUi(WIFI_UNDERLYING_INFO); + assertEquals(NETWORK_ID, wifiRedacted.getWifiInfo().getNetworkId()); + } + + private VcnTransportInfo parcelForSysUi(VcnTransportInfo vcnTransportInfo) { + // Allow fully unredacted; SysUI will have all the relevant permissions. + final VcnTransportInfo unRedacted = (VcnTransportInfo) vcnTransportInfo.makeCopy( + REDACT_NONE); + final Parcel parcel = Parcel.obtain(); + unRedacted.writeToParcel(parcel, 0 /* flags */); + parcel.setDataPosition(0); + + final VcnTransportInfo unparceled = VcnTransportInfo.CREATOR.createFromParcel(parcel); + assertEquals(vcnTransportInfo, unparceled); + return unparceled; } } diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 393787f1a8b8..f3851130c68a 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -52,8 +52,8 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest public class IkeSessionParamsUtilsTest { - // Package private for use in EncryptedTunnelParamsUtilsTest - static IkeSessionParams.Builder createBuilderMinimum() { + // Public for use in VcnGatewayConnectionConfigTest, EncryptedTunnelParamsUtilsTest + public static IkeSessionParams.Builder createBuilderMinimum() { final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100"); // TODO: b/185941731 Make sure all valid IKE_OPTIONS are added and validated. @@ -63,6 +63,7 @@ public class IkeSessionParamsUtilsTest { .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net")) .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net")) .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500) + .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) .setAuthPsk("psk".getBytes()); } diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java index 0c8ad32b0c27..f9dc9eb4d5ae 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java @@ -18,6 +18,7 @@ package android.net.vcn.persistablebundleutils; import static org.junit.Assert.assertEquals; +import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import androidx.test.filters.SmallTest; @@ -31,9 +32,13 @@ import org.junit.runner.RunWith; public class TunnelConnectionParamsUtilsTest { // Public for use in VcnGatewayConnectionConfigTest public static IkeTunnelConnectionParams buildTestParams() { + return buildTestParams(IkeSessionParamsUtilsTest.createBuilderMinimum().build()); + } + + // Public for use in VcnGatewayConnectionConfigTest + public static IkeTunnelConnectionParams buildTestParams(IkeSessionParams params) { return new IkeTunnelConnectionParams( - IkeSessionParamsUtilsTest.createBuilderMinimum().build(), - TunnelModeChildSessionParamsUtilsTest.createBuilderMinimum().build()); + params, TunnelModeChildSessionParamsUtilsTest.createBuilderMinimum().build()); } @Test diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index aa4b5f8e208f..3360d40062a3 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -37,6 +37,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; @@ -66,6 +67,7 @@ import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; +import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.os.IBinder; @@ -77,6 +79,7 @@ import android.os.test.TestLooper; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -98,6 +101,7 @@ import java.io.FileNotFoundException; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -195,7 +199,8 @@ public class VcnManagementServiceTest { .newVcnContext( eq(mMockContext), eq(mTestLooper.getLooper()), - any(VcnNetworkProvider.class)); + any(VcnNetworkProvider.class), + anyBoolean()); doReturn(mSubscriptionTracker) .when(mMockDeps) .newTelephonySubscriptionTracker( @@ -326,6 +331,17 @@ public class VcnManagementServiceTest { return subIdToGroupMap.get(invocation.getArgument(0)); }).when(snapshot).getGroupForSubId(anyInt()); + doAnswer(invocation -> { + final ParcelUuid subGrp = invocation.getArgument(0); + final Set<Integer> subIds = new ArraySet<>(); + for (Entry<Integer, ParcelUuid> entry : subIdToGroupMap.entrySet()) { + if (entry.getValue().equals(subGrp)) { + subIds.add(entry.getKey()); + } + } + return subIds; + }).when(snapshot).getAllSubIdsInGroup(any()); + final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); cb.onNewSnapshot(snapshot); @@ -358,6 +374,12 @@ public class VcnManagementServiceTest { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); verify(mMockDeps) + .newVcnContext( + eq(mMockContext), + eq(mTestLooper.getLooper()), + any(VcnNetworkProvider.class), + anyBoolean()); + verify(mMockDeps) .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any()); } @@ -515,6 +537,28 @@ public class VcnManagementServiceTest { } @Test + public void testSetVcnConfigTestModeRequiresPermission() throws Exception { + doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS")) + .when(mMockContext) + .enforceCallingPermission( + eq(android.Manifest.permission.MANAGE_TEST_NETWORKS), any()); + + final VcnConfig vcnConfig = + new VcnConfig.Builder(mMockContext) + .addGatewayConnectionConfig( + VcnGatewayConnectionConfigTest.buildTestConfig()) + .setIsTestModeProfile() + .build(); + + try { + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME); + fail("Expected exception due to using test-mode without permission"); + } catch (SecurityException e) { + verify(mMockPolicyListener, never()).onPolicyChanged(); + } + } + + @Test public void testSetVcnConfigNotifiesStatusCallback() throws Exception { triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); @@ -914,6 +958,18 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } + @Test + public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception { + startAndGetVcnInstance(TEST_UUID_2); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + triggerSubscriptionTrackerCbAndGetSnapshot( + Collections.singleton(TEST_UUID_2), + Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2)); + + verify(mMockPolicyListener).onPolicyChanged(); + } + private void triggerVcnSafeMode( @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot, diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 528f240b9912..ca7463884d3a 100644 --- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -88,13 +88,13 @@ public class TelephonySubscriptionTrackerTest { private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map<ParcelUuid, Set<String>> TEST_PRIVILEGED_PACKAGES = Collections.singletonMap(TEST_PARCEL_UUID, Collections.singleton(PACKAGE_NAME)); - private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP; + private static final Map<Integer, SubscriptionInfo> TEST_SUBID_TO_INFO_MAP; static { - final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>(); - subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID); - subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID); - TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap); + final Map<Integer, SubscriptionInfo> subIdToGroupMap = new HashMap<>(); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_SUBINFO_1); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_SUBINFO_2); + TEST_SUBID_TO_INFO_MAP = Collections.unmodifiableMap(subIdToGroupMap); } @NonNull private final Context mContext; @@ -190,13 +190,13 @@ public class TelephonySubscriptionTrackerTest { private TelephonySubscriptionSnapshot buildExpectedSnapshot( Map<ParcelUuid, Set<String>> privilegedPackages) { - return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, privilegedPackages); + return buildExpectedSnapshot(TEST_SUBID_TO_INFO_MAP, privilegedPackages); } private TelephonySubscriptionSnapshot buildExpectedSnapshot( - Map<Integer, ParcelUuid> subIdToGroupMap, + Map<Integer, SubscriptionInfo> subIdToInfoMap, Map<ParcelUuid, Set<String>> privilegedPackages) { - return new TelephonySubscriptionSnapshot(subIdToGroupMap, privilegedPackages); + return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages); } private void verifyNoActiveSubscriptions() { @@ -371,7 +371,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap()); + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); @@ -380,7 +380,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap()); + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals( new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 8289e85dadf9..f91575b670d3 100644 --- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -41,12 +42,14 @@ import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.os.ParcelUuid; import android.os.test.TestLooper; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; import android.util.ArraySet; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback; -import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback; +import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkListener; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; @@ -58,7 +61,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Arrays; -import java.util.Collections; import java.util.Set; import java.util.UUID; @@ -97,11 +99,13 @@ public class UnderlyingNetworkTrackerTest { @Mock private Context mContext; @Mock private VcnNetworkProvider mVcnNetworkProvider; @Mock private ConnectivityManager mConnectivityManager; + @Mock private TelephonyManager mTelephonyManager; + @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb; @Mock private Network mNetwork; - @Captor private ArgumentCaptor<RouteSelectionCallback> mRouteSelectionCallbackCaptor; + @Captor private ArgumentCaptor<UnderlyingNetworkListener> mUnderlyingNetworkListenerCaptor; private TestLooper mTestLooper; private VcnContext mVcnContext; @@ -112,14 +116,27 @@ public class UnderlyingNetworkTrackerTest { MockitoAnnotations.initMocks(this); mTestLooper = new TestLooper(); - mVcnContext = spy(new VcnContext(mContext, mTestLooper.getLooper(), mVcnNetworkProvider)); - doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + mVcnContext = + spy( + new VcnContext( + mContext, + mTestLooper.getLooper(), + mVcnNetworkProvider, + false /* isInTestMode */)); + resetVcnContext(); setupSystemService( mContext, mConnectivityManager, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + setupSystemService( + mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + setupSystemService( + mContext, + mCarrierConfigManager, + Context.CARRIER_CONFIG_SERVICE, + CarrierConfigManager.class); when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS); @@ -128,10 +145,14 @@ public class UnderlyingNetworkTrackerTest { mVcnContext, SUB_GROUP, mSubscriptionSnapshot, - Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), mNetworkTrackerCb); } + private void resetVcnContext() { + reset(mVcnContext); + doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + } + private static LinkProperties getLinkPropertiesWithName(String iface) { LinkProperties linkProperties = new LinkProperties(); linkProperties.setInterfaceName(iface); @@ -149,6 +170,30 @@ public class UnderlyingNetworkTrackerTest { verifyNetworkRequestsRegistered(INITIAL_SUB_IDS); } + @Test + public void testNetworkCallbacksRegisteredOnStartupForTestMode() { + final ConnectivityManager cm = mock(ConnectivityManager.class); + setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + final VcnContext vcnContext = + new VcnContext( + mContext, + mTestLooper.getLooper(), + mVcnNetworkProvider, + true /* isInTestMode */); + + new UnderlyingNetworkTracker( + vcnContext, + SUB_GROUP, + mSubscriptionSnapshot, + mNetworkTrackerCb); + + verify(cm) + .registerNetworkCallback( + eq(getTestNetworkRequest(INITIAL_SUB_IDS)), + any(UnderlyingNetworkListener.class), + any()); + } + private void verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( @@ -163,9 +208,20 @@ public class UnderlyingNetworkTrackerTest { } verify(mConnectivityManager) - .requestBackgroundNetwork( + .registerNetworkCallback( eq(getRouteSelectionRequest(expectedSubIds)), - any(RouteSelectionCallback.class), any()); + any(UnderlyingNetworkListener.class), + any()); + verify(mConnectivityManager) + .registerNetworkCallback( + eq(getWifiEntryRssiThresholdRequest(expectedSubIds)), + any(NetworkBringupCallback.class), + any()); + verify(mConnectivityManager) + .registerNetworkCallback( + eq(getWifiExitRssiThresholdRequest(expectedSubIds)), + any(NetworkBringupCallback.class), + any()); } @Test @@ -180,9 +236,10 @@ public class UnderlyingNetworkTrackerTest { mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate); // verify that initially-filed bringup requests are unregistered (cell + wifi) - verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 1)) + verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 3)) .unregisterNetworkCallback(any(NetworkBringupCallback.class)); - verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + verify(mConnectivityManager) + .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); verifyNetworkRequestsRegistered(UPDATED_SUB_IDS); } @@ -193,6 +250,24 @@ public class UnderlyingNetworkTrackerTest { .build(); } + private NetworkRequest getWifiEntryRssiThresholdRequest(Set<Integer> netCapsSubIds) { + // TODO (b/187991063): Add tests for carrier-config based thresholds + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(netCapsSubIds) + .setSignalStrength(UnderlyingNetworkTracker.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) + .build(); + } + + private NetworkRequest getWifiExitRssiThresholdRequest(Set<Integer> netCapsSubIds) { + // TODO (b/187991063): Add tests for carrier-config based thresholds + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(netCapsSubIds) + .setSignalStrength(UnderlyingNetworkTracker.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) + .build(); + } + private NetworkRequest getCellRequestForSubId(int subId) { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) @@ -201,7 +276,19 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) { - return getExpectedRequestBase().setSubscriptionIds(netCapsSubIds).build(); + return getExpectedRequestBase() + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .setSubscriptionIds(netCapsSubIds) + .build(); + } + + private NetworkRequest getTestNetworkRequest(Set<Integer> netCapsSubIds) { + return new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setSubscriptionIds(netCapsSubIds) + .build(); } private NetworkRequest.Builder getExpectedRequestBase() { @@ -219,11 +306,12 @@ public class UnderlyingNetworkTrackerTest { public void testTeardown() { mUnderlyingNetworkTracker.teardown(); - // Expect 3 NetworkBringupCallbacks to be unregistered: 1 for WiFi and 2 for Cellular (1x - // for each subId) - verify(mConnectivityManager, times(3)) + // Expect 5 NetworkBringupCallbacks to be unregistered: 1 for WiFi, 2 for Cellular (1x for + // each subId), and 1 for each of the Wifi signal strength thresholds + verify(mConnectivityManager, times(5)) .unregisterNetworkCallback(any(NetworkBringupCallback.class)); - verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + verify(mConnectivityManager) + .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); } @Test @@ -256,19 +344,19 @@ public class UnderlyingNetworkTrackerTest { verifyRegistrationOnAvailableAndGetCallback(); } - private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback() { + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() { return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); } - private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback( + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback( NetworkCapabilities networkCapabilities) { verify(mConnectivityManager) - .requestBackgroundNetwork( + .registerNetworkCallback( eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), - mRouteSelectionCallbackCaptor.capture(), + mUnderlyingNetworkListenerCaptor.capture(), any()); - RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue(); + UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue(); cb.onAvailable(mNetwork); cb.onCapabilitiesChanged(mNetwork, networkCapabilities); cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES); @@ -286,7 +374,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); @@ -301,7 +389,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES); @@ -316,7 +404,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkSuspended() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); @@ -335,7 +423,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkResumed() { - RouteSelectionCallback cb = + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES); cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); @@ -355,7 +443,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForBlocked() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); @@ -370,7 +458,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkLoss() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onLost(mNetwork); @@ -379,7 +467,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackIgnoresDuplicateRecord() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); @@ -387,4 +475,6 @@ public class UnderlyingNetworkTrackerTest { // UnderlyingNetworkRecord does not actually change verifyNoMoreInteractions(mNetworkTrackerCb); } + + // TODO (b/187991063): Add tests for network prioritization } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 530e63699e9f..39f7386cbb76 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -16,8 +16,11 @@ package com.android.server.vcn; +import static android.net.IpSecManager.DIRECTION_FWD; import static android.net.IpSecManager.DIRECTION_IN; import static android.net.IpSecManager.DIRECTION_OUT; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; @@ -51,10 +54,11 @@ import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager.VcnErrorCode; import androidx.test.filters.SmallTest; @@ -144,8 +148,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); } - @Test - public void testCreatedTransformsAreApplied() throws Exception { + private void verifyVcnTransformsApplied( + VcnGatewayConnection vcnGatewayConnection, boolean expectForwardTransform) + throws Exception { for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction); mTestLooper.dispatchAll(); @@ -155,7 +160,40 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); } - assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + verify(mIpSecSvc, expectForwardTransform ? times(1) : never()) + .applyTunnelModeTransform( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(DIRECTION_FWD), anyInt(), any()); + + assertEquals(vcnGatewayConnection.mConnectedState, vcnGatewayConnection.getCurrentState()); + } + + @Test + public void testCreatedTransformsAreApplied() throws Exception { + verifyVcnTransformsApplied(mGatewayConnection, false /* expectForwardTransform */); + } + + @Test + public void testCreatedTransformsAreAppliedWithDun() throws Exception { + VcnGatewayConnectionConfig gatewayConfig = + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps( + NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN); + VcnGatewayConnection gatewayConnection = + new VcnGatewayConnection( + mVcnContext, + TEST_SUB_GRP, + TEST_SUBSCRIPTION_SNAPSHOT, + gatewayConfig, + mGatewayStatusCallback, + true /* isMobileDataEnabled */, + mDeps); + gatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); + final VcnIkeSession session = + gatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network); + gatewayConnection.setIkeSession(session); + gatewayConnection.transitionTo(gatewayConnection.mConnectedState); + mTestLooper.dispatchAll(); + + verifyVcnTransformsApplied(gatewayConnection, true /* expectForwardTransform */); } @Test @@ -181,7 +219,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); final List<ChildSaProposal> saProposals = - ((IkeTunnelConnectionParams) mConfig.getTunnelConnectionParams()) + mConfig.getTunnelConnectionParams() .getTunnelModeChildSessionParams() .getSaProposals(); final int expectedMtu = @@ -344,6 +382,31 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertFalse(mGatewayConnection.isInSafeMode()); } + @Test + public void testSubsequentFailedValidationTriggersSafeMode() throws Exception { + triggerChildOpened(); + mTestLooper.dispatchAll(); + + triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); + assertFalse(mGatewayConnection.isInSafeMode()); + + // Trigger a failed validation, and the subsequent safemode timeout. + triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID); + mTestLooper.dispatchAll(); + + final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mDeps, times(2)) + .newWakeupMessage( + eq(mVcnContext), + any(), + eq(VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM), + runnableCaptor.capture()); + runnableCaptor.getValue().run(); + mTestLooper.dispatchAll(); + + assertTrue(mGatewayConnection.isInSafeMode()); + } + private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() { triggerChildOpened(); mTestLooper.dispatchAll(); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 044bef5b002f..a88f112f4502 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -38,7 +38,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect public void setUp() throws Exception { super.setUp(); - mFirstRetryInterval = mConfig.getRetryIntervalsMs()[0]; + mFirstRetryInterval = mConfig.getRetryIntervalsMillis()[0]; mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 284f1f88658e..860a919aa9b3 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -54,6 +54,7 @@ import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.test.TestLooper; +import android.telephony.SubscriptionInfo; import com.android.internal.util.State; import com.android.internal.util.WakeupMessage; @@ -73,6 +74,12 @@ import java.util.concurrent.TimeUnit; public class VcnGatewayConnectionTestBase { protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); + protected static final SubscriptionInfo TEST_SUB_INFO = mock(SubscriptionInfo.class); + + static { + doReturn(TEST_SUB_GRP).when(TEST_SUB_INFO).getGroupUuid(); + } + protected static final InetAddress TEST_DNS_ADDR = InetAddresses.parseNumericAddress("2001:DB8:0:1::"); protected static final InetAddress TEST_DNS_ADDR_2 = @@ -116,7 +123,7 @@ public class VcnGatewayConnectionTestBase { protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = new TelephonySubscriptionSnapshot( - Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP); + Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP); @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; @@ -166,7 +173,7 @@ public class VcnGatewayConnectionTestBase { doReturn(mUnderlyingNetworkTracker) .when(mDeps) - .newUnderlyingNetworkTracker(any(), any(), any(), any(), any()); + .newUnderlyingNetworkTracker(any(), any(), any(), any()); doReturn(mWakeLock) .when(mDeps) .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any()); @@ -220,7 +227,7 @@ public class VcnGatewayConnectionTestBase { protected VcnChildSessionCallback getChildSessionCallback() { ArgumentCaptor<ChildSessionCallback> captor = ArgumentCaptor.forClass(ChildSessionCallback.class); - verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture()); + verify(mDeps, atLeastOnce()).newIkeSession(any(), any(), any(), any(), captor.capture()); return (VcnChildSessionCallback) captor.getValue(); } diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java index 736fabdb1ac5..f681ee19ab12 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java @@ -388,8 +388,9 @@ public class VcnTest { final ContentObserver contentObserver = captor.getValue(); // Start VcnGatewayConnections + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); mVcn.setMobileDataEnabled(startingToggleState); - triggerVcnRequestListeners(verifyAndGetRequestListener()); + triggerVcnRequestListeners(requestListener); final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> gateways = mVcn.getVcnGatewayConnectionConfigMap(); @@ -411,6 +412,9 @@ public class VcnTest { } } + if (startingToggleState != endingToggleState) { + verify(mVcnNetworkProvider).resendAllRequests(requestListener); + } assertEquals(endingToggleState, mVcn.isMobileDataEnabled()); } diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp index 5c47e0fa8a16..4e8dcb1bc6ee 100644 --- a/tools/aapt/pseudolocalize.cpp +++ b/tools/aapt/pseudolocalize.cpp @@ -194,7 +194,8 @@ static String16 pseudo_generate_expansion(const unsigned int length) { break; } } - result.remove(length + ext, 0); + // Just keep the first length + ext characters + result = String16(result, length + ext); } return result; } |