diff options
152 files changed, 2257 insertions, 1052 deletions
diff --git a/Android.bp b/Android.bp index b739c43bb776..5211fe23e1bb 100644 --- a/Android.bp +++ b/Android.bp @@ -506,6 +506,9 @@ java_library { }, lint: { baseline_filename: "lint-baseline.xml", + warning_checks: [ + "FlaggedApi", + ], }, jarjar_prefix: "com.android.internal.hidden_from_bootclasspath", } diff --git a/BAL_OWNERS b/BAL_OWNERS index d56a1d4634df..ec779e76fa3b 100644 --- a/BAL_OWNERS +++ b/BAL_OWNERS @@ -2,4 +2,6 @@ brufino@google.com achim@google.com topjohnwu@google.com lus@google.com +haok@google.com +wnan@google.com diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java index 4bcc8c499f0d..f302033dee0f 100644 --- a/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java +++ b/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java @@ -31,6 +31,7 @@ import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; +import android.permission.PermissionManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; @@ -107,6 +108,8 @@ public class PackageManagerPerfTest { public void setup() { PackageManager.disableApplicationInfoCache(); PackageManager.disablePackageInfoCache(); + PermissionManager.disablePermissionCache(); + PermissionManager.disablePackageNamePermissionCache(); } @Test diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp index ace56d42ddd1..06c7d64d1708 100644 --- a/apex/jobscheduler/service/Android.bp +++ b/apex/jobscheduler/service/Android.bp @@ -24,6 +24,7 @@ java_library { "app-compat-annotations", "error_prone_annotations", "framework", + "keepanno-annotations", "services.core", "unsupportedappusage", ], diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 19bc7160e16a..613678bedf8a 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -130,6 +130,8 @@ import com.android.server.AppSchedulingModuleThread; import com.android.server.LocalServices; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.usage.AppIdleHistory.AppUsageHistory; +import com.android.tools.r8.keepanno.annotations.KeepItemKind; +import com.android.tools.r8.keepanno.annotations.UsedByReflection; import libcore.util.EmptyArray; @@ -588,6 +590,8 @@ public class AppStandbyController } } + // This constructor is reflectively invoked from framework code in AppStandbyInternal. + @UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS) public AppStandbyController(Context context) { this(new Injector(context, AppSchedulingModuleThread.get().getLooper())); } diff --git a/api/Android.bp b/api/Android.bp index bf4e6a11d25a..4de3a28db88b 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -29,12 +29,14 @@ bootstrap_go_package { pkgPath: "android/soong/api", deps: [ "blueprint", + "blueprint-proptools", "soong", "soong-android", "soong-genrule", "soong-java", ], srcs: ["api.go"], + testSrcs: ["api_test.go"], pluginFor: ["soong_build"], } @@ -365,8 +367,6 @@ stubs_defaults { "--hide CallbackInterface", // Disable HiddenSuperclass, as Metalava handles this fine (it should be hidden by default) "--hide HiddenSuperclass", - "--hide-package android.audio.policy.configuration.V7_0", - "--hide-package com.android.server", "--manifest $(location :frameworks-base-core-AndroidManifest.xml)", ], filter_packages: packages_to_document, diff --git a/api/api.go b/api/api.go index d4db49e90a01..f0d1f42f61d4 100644 --- a/api/api.go +++ b/api/api.go @@ -54,11 +54,11 @@ var non_updatable_modules = []string{virtualization, location} // The properties of the combined_apis module type. type CombinedApisProperties struct { // Module libraries in the bootclasspath - Bootclasspath []string + Bootclasspath proptools.Configurable[[]string] // Module libraries on the bootclasspath if include_nonpublic_framework_api is true. Conditional_bootclasspath []string // Module libraries in system server - System_server_classpath []string + System_server_classpath proptools.Configurable[[]string] } type CombinedApis struct { @@ -79,29 +79,37 @@ func registerBuildComponents(ctx android.RegistrationContext) { var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents) -func (a *CombinedApis) apiFingerprintStubDeps() []string { +func (a *CombinedApis) bootclasspath(ctx android.ConfigAndErrorContext) []string { + return a.properties.Bootclasspath.GetOrDefault(a.ConfigurableEvaluator(ctx), nil) +} + +func (a *CombinedApis) systemServerClasspath(ctx android.ConfigAndErrorContext) []string { + return a.properties.System_server_classpath.GetOrDefault(a.ConfigurableEvaluator(ctx), nil) +} + +func (a *CombinedApis) apiFingerprintStubDeps(ctx android.BottomUpMutatorContext) []string { ret := []string{} ret = append( ret, - transformArray(a.properties.Bootclasspath, "", ".stubs")..., + transformArray(a.bootclasspath(ctx), "", ".stubs")..., ) ret = append( ret, - transformArray(a.properties.Bootclasspath, "", ".stubs.system")..., + transformArray(a.bootclasspath(ctx), "", ".stubs.system")..., ) ret = append( ret, - transformArray(a.properties.Bootclasspath, "", ".stubs.module_lib")..., + transformArray(a.bootclasspath(ctx), "", ".stubs.module_lib")..., ) ret = append( ret, - transformArray(a.properties.System_server_classpath, "", ".stubs.system_server")..., + transformArray(a.systemServerClasspath(ctx), "", ".stubs.system_server")..., ) return ret } func (a *CombinedApis) DepsMutator(ctx android.BottomUpMutatorContext) { - ctx.AddDependency(ctx.Module(), nil, a.apiFingerprintStubDeps()...) + ctx.AddDependency(ctx.Module(), nil, a.apiFingerprintStubDeps(ctx)...) } func (a *CombinedApis) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -532,8 +540,8 @@ func createFullExportableApiLibraries(ctx android.LoadHookContext) { } func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { - bootclasspath := a.properties.Bootclasspath - system_server_classpath := a.properties.System_server_classpath + bootclasspath := a.bootclasspath(ctx) + system_server_classpath := a.systemServerClasspath(ctx) if ctx.Config().VendorConfig("ANDROID").Bool("include_nonpublic_framework_api") { bootclasspath = append(bootclasspath, a.properties.Conditional_bootclasspath...) sort.Strings(bootclasspath) diff --git a/api/api_test.go b/api/api_test.go new file mode 100644 index 000000000000..47d167093b39 --- /dev/null +++ b/api/api_test.go @@ -0,0 +1,254 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 api + +import ( + "android/soong/android" + "android/soong/java" + "fmt" + "testing" + + "github.com/google/blueprint/proptools" +) + +var prepareForTestWithCombinedApis = android.GroupFixturePreparers( + android.FixtureRegisterWithContext(registerBuildComponents), + java.PrepareForTestWithJavaBuildComponents, + android.FixtureAddTextFile("a/Android.bp", gatherRequiredDepsForTest()), + java.PrepareForTestWithJavaSdkLibraryFiles, + android.FixtureMergeMockFs(android.MockFS{ + "a/api/current.txt": nil, + "a/api/removed.txt": nil, + "a/api/system-current.txt": nil, + "a/api/system-removed.txt": nil, + "a/api/test-current.txt": nil, + "a/api/test-removed.txt": nil, + "a/api/module-lib-current.txt": nil, + "a/api/module-lib-removed.txt": nil, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Allow_missing_dependencies = proptools.BoolPtr(true) + }), +) + +func gatherRequiredDepsForTest() string { + var bp string + + extraLibraryModules := []string{ + "stable.core.platform.api.stubs", + "core-lambda-stubs", + "core.current.stubs", + "ext", + "framework", + "android_stubs_current.from-text", + "android_system_stubs_current.from-text", + "android_test_stubs_current.from-text", + "android_test_frameworks_core_stubs_current.from-text", + "android_module_lib_stubs_current.from-text", + "android_system_server_stubs_current.from-text", + "android_stubs_current.from-source", + "android_system_stubs_current.from-source", + "android_test_stubs_current.from-source", + "android_test_frameworks_core_stubs_current.from-source", + "android_module_lib_stubs_current.from-source", + "android_system_server_stubs_current.from-source", + "android_stubs_current_exportable.from-source", + "android_system_stubs_current_exportable.from-source", + "android_test_stubs_current_exportable.from-source", + "android_module_lib_stubs_current_exportable.from-source", + "android_system_server_stubs_current_exportable.from-source", + "stub-annotations", + } + + extraSdkLibraryModules := []string{ + "framework-virtualization", + "framework-location", + } + + extraSystemModules := []string{ + "core-public-stubs-system-modules", + "core-module-lib-stubs-system-modules", + "stable-core-platform-api-stubs-system-modules", + } + + extraFilegroupModules := []string{ + "non-updatable-current.txt", + "non-updatable-removed.txt", + "non-updatable-system-current.txt", + "non-updatable-system-removed.txt", + "non-updatable-test-current.txt", + "non-updatable-test-removed.txt", + "non-updatable-module-lib-current.txt", + "non-updatable-module-lib-removed.txt", + "non-updatable-system-server-current.txt", + "non-updatable-system-server-removed.txt", + "non-updatable-exportable-current.txt", + "non-updatable-exportable-removed.txt", + "non-updatable-exportable-system-current.txt", + "non-updatable-exportable-system-removed.txt", + "non-updatable-exportable-test-current.txt", + "non-updatable-exportable-test-removed.txt", + "non-updatable-exportable-module-lib-current.txt", + "non-updatable-exportable-module-lib-removed.txt", + "non-updatable-exportable-system-server-current.txt", + "non-updatable-exportable-system-server-removed.txt", + } + + for _, extra := range extraLibraryModules { + bp += fmt.Sprintf(` + java_library { + name: "%s", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "stable-core-platform-api-stubs-system-modules", + compile_dex: true, + } + `, extra) + } + + for _, extra := range extraSdkLibraryModules { + bp += fmt.Sprintf(` + java_sdk_library { + name: "%s", + srcs: ["a.java"], + public: { + enabled: true, + }, + system: { + enabled: true, + }, + test: { + enabled: true, + }, + module_lib: { + enabled: true, + }, + api_packages: [ + "foo", + ], + sdk_version: "core_current", + compile_dex: true, + annotations_enabled: true, + } + `, extra) + } + + for _, extra := range extraFilegroupModules { + bp += fmt.Sprintf(` + filegroup { + name: "%[1]s", + } + `, extra) + } + + for _, extra := range extraSystemModules { + bp += fmt.Sprintf(` + java_system_modules { + name: "%[1]s", + libs: ["%[1]s-lib"], + } + java_library { + name: "%[1]s-lib", + sdk_version: "none", + system_modules: "none", + } + `, extra) + } + + bp += fmt.Sprintf(` + java_defaults { + name: "android.jar_defaults", + } + `) + + return bp +} + +func TestCombinedApisDefaults(t *testing.T) { + + result := android.GroupFixturePreparers( + prepareForTestWithCombinedApis, + java.FixtureWithLastReleaseApis( + "framework-location", "framework-virtualization", "framework-foo", "framework-bar"), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.VendorVars = map[string]map[string]string{ + "boolean_var": { + "for_testing": "true", + }, + } + }), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "framework-foo", + srcs: ["a.java"], + public: { + enabled: true, + }, + system: { + enabled: true, + }, + test: { + enabled: true, + }, + module_lib: { + enabled: true, + }, + api_packages: [ + "foo", + ], + sdk_version: "core_current", + annotations_enabled: true, + } + + java_sdk_library { + name: "framework-bar", + srcs: ["a.java"], + public: { + enabled: true, + }, + system: { + enabled: true, + }, + test: { + enabled: true, + }, + module_lib: { + enabled: true, + }, + api_packages: [ + "foo", + ], + sdk_version: "core_current", + annotations_enabled: true, + } + + combined_apis { + name: "foo", + bootclasspath: [ + "framework-bar", + ] + select(boolean_var_for_testing(), { + true: [ + "framework-foo", + ], + default: [], + }), + } + `) + + subModuleDependsOnSelectAppendedModule := java.CheckModuleHasDependency(t, + result.TestContext, "foo-current.txt", "", "framework-foo") + android.AssertBoolEquals(t, "Submodule expected to depend on the select-appended module", + true, subModuleDependsOnSelectAppendedModule) +} diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt index 5efda98a1518..0a3ae4f790b0 100644 --- a/api/coverage/tools/ExtractFlaggedApis.kt +++ b/api/coverage/tools/ExtractFlaggedApis.kt @@ -16,9 +16,9 @@ package android.platform.coverage +import com.android.tools.metalava.model.CallableItem import com.android.tools.metalava.model.ClassItem import com.android.tools.metalava.model.Item -import com.android.tools.metalava.model.MethodItem import com.android.tools.metalava.model.text.ApiFile import java.io.File import java.io.FileWriter @@ -40,24 +40,24 @@ fun main(args: Array<String>) { fun extractFlaggedApisFromClass( classItem: ClassItem, - methods: List<MethodItem>, + callables: List<CallableItem>, packageName: String, builder: FlagApiMap.Builder ) { - if (methods.isEmpty()) return + if (callables.isEmpty()) return val classFlag = getClassFlag(classItem) - for (method in methods) { - val methodFlag = getFlagAnnotation(method) ?: classFlag + for (callable in callables) { + val callableFlag = getFlagAnnotation(callable) ?: classFlag val api = JavaMethod.newBuilder() .setPackageName(packageName) .setClassName(classItem.fullName()) - .setMethodName(method.name()) - for (param in method.parameters()) { + .setMethodName(callable.name()) + for (param in callable.parameters()) { api.addParameters(param.type().toTypeString()) } - if (methodFlag != null) { - addFlaggedApi(builder, api, methodFlag) + if (callableFlag != null) { + addFlaggedApi(builder, api, callableFlag) } } } @@ -75,10 +75,10 @@ fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: St fun getClassFlag(classItem: ClassItem): String? { var classFlag = getFlagAnnotation(classItem) var cur = classItem - // If a class is not an inner class, use its @FlaggedApi annotation value. + // If a class is not a nested class, use its @FlaggedApi annotation value. // Otherwise, use the flag value of the closest outer class that is annotated by @FlaggedApi. - while (cur.isInnerClass() && classFlag == null) { - cur = cur.parent() as ClassItem + while (classFlag == null) { + cur = cur.containingClass() ?: break classFlag = getFlagAnnotation(cur) } return classFlag diff --git a/api/gen_combined_removed_dex.sh b/api/gen_combined_removed_dex.sh index e0153f7c1091..2860e2ed17c2 100755 --- a/api/gen_combined_removed_dex.sh +++ b/api/gen_combined_removed_dex.sh @@ -6,6 +6,6 @@ shift 2 # Convert each removed.txt to the "dex format" equivalent, and print all output. for f in "$@"; do - "$metalava_path" signature-to-dex "$f" "${tmp_dir}/tmp" + "$metalava_path" signature-to-dex "$f" --out "${tmp_dir}/tmp" cat "${tmp_dir}/tmp" done diff --git a/api/go.work b/api/go.work index edd002e7efba..c09bee578b61 100644 --- a/api/go.work +++ b/api/go.work @@ -1,17 +1,17 @@ -go 1.18 +go 1.22 use ( . - ../../../build/soong ../../../build/blueprint + ../../../build/soong ../../../external/go-cmp ../../../external/golang-protobuf ) replace ( android/soong v0.0.0 => ../../../build/soong - google.golang.org/protobuf v0.0.0 => ../../../external/golang-protobuf github.com/google/blueprint v0.0.0 => ../../../build/blueprint github.com/google/go-cmp v0.0.0 => ../../../external/go-cmp go.starlark.net v0.0.0 => ../../../external/starlark-go + google.golang.org/protobuf v0.0.0 => ../../../external/golang-protobuf ) diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 7eb9d0f3ea91..fdf9abc49604 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -236,7 +236,7 @@ void BootAnimation::onFirstRef() { ALOGD("%sAnimationPreloadTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime()); preloadAnimation(); - ALOGD("%sAnimationPreloadStopTiming start time: %" PRId64 "ms", + ALOGD("%sAnimationPreloadTiming stop time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime()); } } diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 9c1a8e854e92..7bf06b4afc3d 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -271,12 +271,12 @@ package android.net { method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderLimitReached(); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningReached(); - method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback); - method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback); + method @Deprecated @FlaggedApi("android.net.platform.flags.deprecate_network_policy_callback") @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback); + method @Deprecated @FlaggedApi("android.net.platform.flags.deprecate_network_policy_callback") @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback); } - public static interface NetworkPolicyManager.NetworkPolicyCallback { - method public default void onUidBlockedReasonChanged(int, int); + @Deprecated @FlaggedApi("android.net.platform.flags.deprecate_network_policy_callback") public static interface NetworkPolicyManager.NetworkPolicyCallback { + method @Deprecated public default void onUidBlockedReasonChanged(int, int); } public class NetworkWatchlistManager { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 5aa89b98353f..805cfb7b115d 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3738,6 +3738,7 @@ package android.content { method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle); method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable android.app.BroadcastOptions); + method @FlaggedApi("android.os.ordered_broadcast_multiple_permissions") public void sendOrderedBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle, @Nullable android.os.Bundle); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle); field public static final String AMBIENT_CONTEXT_SERVICE = "ambient_context"; diff --git a/core/java/android/animation/OWNERS b/core/java/android/animation/OWNERS index f3b330a02116..5223c870824c 100644 --- a/core/java/android/animation/OWNERS +++ b/core/java/android/animation/OWNERS @@ -3,3 +3,4 @@ romainguy@google.com tianliu@google.com adamp@google.com +mount@google.com diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index ee82b3f6ad02..76e761d62f20 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -3678,7 +3678,9 @@ public class Activity extends ContextThemeWrapper * @see View#findViewById(int) * @see Activity#requireViewById(int) */ - /* TODO(b/347672184): Re-add @Nullable */ + // Strictly speaking this should be marked as @Nullable but the nullability of the return value + // is deliberately left unspecified as idiomatically correct code can make assumptions either + // way based on local context, e.g. layout specification. public <T extends View> T findViewById(@IdRes int id) { return getWindow().findViewById(id); } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index af56cb4d55b2..d1bd88cfd1d8 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1524,6 +1524,17 @@ class ContextImpl extends Context { public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { + String[] receiverPermissions = receiverPermission == null ? null + : new String[] {receiverPermission}; + sendOrderedBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions, appOp, + options, resultReceiver, scheduler, initialCode, initialData, initialExtras); + } + + @Override + public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions, int appOp, Bundle options, + BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, + String initialData, Bundle initialExtras) { IIntentReceiver rd = null; if (resultReceiver != null) { if (mPackageInfo != null) { @@ -1543,8 +1554,6 @@ class ContextImpl extends Context { } } String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); - String[] receiverPermissions = receiverPermission == null ? null - : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); ActivityManager.getService().broadcastIntentWithFeature( @@ -1571,6 +1580,20 @@ class ContextImpl extends Context { } @Override + public void sendOrderedBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions, + String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, + int initialCode, String initialData, @Nullable Bundle initialExtras, + @Nullable Bundle options) { + int intAppOp = AppOpsManager.OP_NONE; + if (!TextUtils.isEmpty(receiverAppOp)) { + intAppOp = AppOpsManager.strOpToOp(receiverAppOp); + } + sendOrderedBroadcastAsUserMultiplePermissions(intent, getUser(), receiverPermissions, + intAppOp, options, resultReceiver, scheduler, initialCode, initialData, + initialExtras); + } + + @Override public void sendOrderedBroadcast(Intent intent, int initialCode, String receiverPermission, String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, String initialData, @Nullable Bundle initialExtras, Bundle options) { diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 160d00c8a269..d73d536c4675 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -565,7 +565,9 @@ public class Dialog implements DialogInterface, Window.Callback, * @see View#findViewById(int) * @see Dialog#requireViewById(int) */ - /* TODO(b/347672184): Re-add @Nullable */ + // Strictly speaking this should be marked as @Nullable but the nullability of the return value + // is deliberately left unspecified as idiomatically correct code can make assumptions either + // way based on local context, e.g. layout specification. public <T extends View> T findViewById(@IdRes int id) { return mWindow.findViewById(id); } diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 0fad979e27cf..1200b4b45712 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -118,6 +118,8 @@ per-file *Task* = file:/services/core/java/com/android/server/wm/OWNERS per-file Window* = file:/services/core/java/com/android/server/wm/OWNERS per-file ConfigurationController.java = file:/services/core/java/com/android/server/wm/OWNERS per-file *ScreenCapture* = file:/services/core/java/com/android/server/wm/OWNERS +per-file ComponentOptions.java = file:/services/core/java/com/android/server/wm/OWNERS + # Multitasking per-file multitasking.aconfig = file:/services/core/java/com/android/server/wm/OWNERS diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS index 308f1d622c25..4f3f5d9c3535 100644 --- a/core/java/android/app/admin/OWNERS +++ b/core/java/android/app/admin/OWNERS @@ -1,7 +1,6 @@ # Bug component: 142675 # Assign bugs to device-policy-manager-triage@google.com -file:WorkDeviceExperience_OWNERS file:EnterprisePlatformSecurity_OWNERS yamasani@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file diff --git a/core/java/android/app/assist/OWNERS b/core/java/android/app/assist/OWNERS index e4ffd7f41aa0..b53bdc202a89 100644 --- a/core/java/android/app/assist/OWNERS +++ b/core/java/android/app/assist/OWNERS @@ -1,2 +1 @@ -hackz@google.com -volnov@google.com
\ No newline at end of file +srazdan@google.com diff --git a/core/java/android/audio/policy/configuration/V7_0/package-info.java b/core/java/android/audio/policy/configuration/V7_0/package-info.java new file mode 100644 index 000000000000..8f7425fc2b5b --- /dev/null +++ b/core/java/android/audio/policy/configuration/V7_0/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Hide the android.audio.policy.configuration.V7_0 API as that is managed + * separately. + * + * @hide + */ +package android.audio.policy.configuration.V7_0; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index a6eed50a594a..b121da37fd40 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2916,6 +2916,23 @@ public abstract class Context { @Nullable String initialData, @Nullable Bundle initialExtras); /** + * Similar to above but takes array of names of permissions that a receiver must hold in order + * to receive your broadcast. If empty, no permissions are required. + * + * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String, + * BroadcastReceiver, Handler, int, String, Bundle) + * @hide + */ + @SuppressWarnings("HiddenAbstractMethod") + @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) + public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, + UserHandle user, String[] receiverPermissions, int appOp, Bundle options, + BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, + String initialData, Bundle initialExtras) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * Version of * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, * Bundle)} that allows you to specify the App Op to enforce restrictions on which receivers @@ -2997,6 +3014,21 @@ public abstract class Context { } /** + * Like {@link #sendOrderedBroadcast(Intent, String, String, BroadcastReceiver, Handler, int, + * String, Bundle)}, but also allows specification of a list of multiple permissions. + * @hide + */ + @FlaggedApi(Flags.FLAG_ORDERED_BROADCAST_MULTIPLE_PERMISSIONS) + @SystemApi + public void sendOrderedBroadcastMultiplePermissions( + @NonNull Intent intent, @NonNull String[] receiverPermissions, + @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver, + @Nullable Handler scheduler, int initialCode, @Nullable String initialData, + @Nullable Bundle initialExtras, @Nullable Bundle options) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the * Intent you are sending stays around after the broadcast is complete, * so that others can quickly retrieve that data through the return diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index a475c2925881..79fa6ea4d157 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -652,6 +652,16 @@ public class ContextWrapper extends Context { resultReceiver, scheduler, initialCode, initialData, initialExtras); } + /** @hide */ + @Override + public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + @Nullable String[] receiverPermission, int appOp, @Nullable Bundle options, + @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, + int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) { + mBase.sendOrderedBroadcastAsUserMultiplePermissions(intent, user, receiverPermission, appOp, + options, resultReceiver, scheduler, initialCode, initialData, initialExtras); + } + @Override public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent, @Nullable String receiverPermission, @Nullable String receiverAppOp, @@ -661,6 +671,17 @@ public class ContextWrapper extends Context { scheduler, initialCode, initialData, initialExtras); } + /** @hide */ + @Override + public void sendOrderedBroadcastMultiplePermissions( + @NonNull Intent intent, @NonNull String[] receiverPermissions, + @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver, + @Nullable Handler scheduler, int initialCode, @Nullable String initialData, + @Nullable Bundle initialExtras, @Nullable Bundle options) { + mBase.sendOrderedBroadcastMultiplePermissions(intent, receiverPermissions, receiverAppOp, + resultReceiver, scheduler, initialCode, initialData, initialExtras, options); + } + @Override public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent, int initialCode, @Nullable String receiverPermission, @Nullable String receiverAppOp, diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS index 51ad1519941b..43d3f5466ccf 100644 --- a/core/java/android/hardware/OWNERS +++ b/core/java/android/hardware/OWNERS @@ -5,7 +5,7 @@ michaelwr@google.com sumir@google.com # Camera -per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com +per-file *Camera*=file:platform/frameworks/av:/camera/OWNERS # Sensor Privacy per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 334b2316b268..3e6bbf6cdd0c 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -21,6 +21,7 @@ import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.ActivityManager.procStateToString; import static android.content.pm.PackageManager.GET_SIGNATURES; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -36,6 +37,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; +import android.net.platform.flags.Flags; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.os.Build; @@ -954,11 +956,24 @@ public class NetworkPolicyManager { * @param executor The {@link Executor} to run the callback on. * @param callback The {@link NetworkPolicyCallback} to be registered. * @hide + * + * @deprecated This API is only supported up to Android version + * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. On later versions, + * {@link android.net.ConnectivityManager.NetworkCallback} should be used wherever possible. + * + * @throws UnsupportedOperationException when called on Android versions after + * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. */ + @Deprecated + @FlaggedApi(Flags.FLAG_DEPRECATE_NETWORK_POLICY_CALLBACK) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable Executor executor, @NonNull NetworkPolicyCallback callback) { + if (Flags.deprecateNetworkPolicyCallback()) { + throw new UnsupportedOperationException("NetworkPolicyCallback is no longer supported." + + " Please use ConnectivityManager APIs instead"); + } if (callback == null) { throw new NullPointerException("Callback cannot be null."); } @@ -974,10 +989,23 @@ public class NetworkPolicyManager { * * @param callback The {@link NetworkPolicyCallback} to be unregistered. * @hide + * + * @deprecated This API is only supported up to Android version + * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. On later versions, + * {@link android.net.ConnectivityManager.NetworkCallback} should be used wherever possible. + * + * @throws UnsupportedOperationException when called on Android versions after + * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. */ + @Deprecated + @FlaggedApi(Flags.FLAG_DEPRECATE_NETWORK_POLICY_CALLBACK) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull NetworkPolicyCallback callback) { + if (Flags.deprecateNetworkPolicyCallback()) { + throw new UnsupportedOperationException("NetworkPolicyCallback is no longer supported." + + " Please use ConnectivityManager APIs instead"); + } if (callback == null) { throw new NullPointerException("Callback cannot be null."); } @@ -990,8 +1018,18 @@ public class NetworkPolicyManager { /** * Interface for the callback to listen for changes to network blocked status of apps. * + * @deprecated This API is only supported up to Android version + * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. On later versions, this callback will + * <b>not</b> be called when the network blocked status of an app changes. Instead, + * {@link android.net.ConnectivityManager.NetworkCallback} should be used wherever possible. + * + * @see #registerNetworkPolicyCallback(Executor, NetworkPolicyCallback) + * @see #unregisterNetworkPolicyCallback(NetworkPolicyCallback) + * * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_NETWORK_POLICY_CALLBACK) + @Deprecated @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public interface NetworkPolicyCallback { /** diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig index 048c50eb0a19..48eb9680e647 100644 --- a/core/java/android/net/flags.aconfig +++ b/core/java/android/net/flags.aconfig @@ -25,3 +25,13 @@ flag { description: "Flag for registerOffloadEngine API in NsdManager" bug: "294777050" } + +flag { + name: "deprecate_network_policy_callback" + namespace: "backstage_power" + description: "Flag for deprecating NetworkPolicyCallback and related APIs" + bug: "353342610" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/os/DeadObjectException.java b/core/java/android/os/DeadObjectException.java index fc3870e812a2..0a50778dce72 100644 --- a/core/java/android/os/DeadObjectException.java +++ b/core/java/android/os/DeadObjectException.java @@ -26,7 +26,7 @@ import android.os.RemoteException; * receive this error from an app, at a minimum, you should * recover by resetting the connection. For instance, you should * drop the binder, clean up associated state, and reset your - * connection to the service which through this error. In order + * connection to the service which threw this error. In order * to simplify your error recovery paths, you may also want to * "simply" restart your process. However, this may not be an * option if the service you are talking to is unreliable or diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index c9f207cf26e8..50242bad191b 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -29,7 +29,7 @@ import java.io.FileDescriptor; * interface describes the abstract protocol for interacting with a * remotable object. Do not implement this interface directly, instead * extend from {@link Binder}. - * + * * <p>The key IBinder API is {@link #transact transact()} matched by * {@link Binder#onTransact Binder.onTransact()}. These * methods allow you to send a call to an IBinder object and receive a @@ -40,7 +40,7 @@ import java.io.FileDescriptor; * expected behavior when calling an object that exists in the local * process, and the underlying inter-process communication (IPC) mechanism * ensures that these same semantics apply when going across processes. - * + * * <p>The data sent through transact() is a {@link Parcel}, a generic buffer * of data that also maintains some meta-data about its contents. The meta * data is used to manage IBinder object references in the buffer, so that those @@ -51,7 +51,7 @@ import java.io.FileDescriptor; * same IBinder object back. These semantics allow IBinder/Binder objects to * be used as a unique identity (to serve as a token or for other purposes) * that can be managed across processes. - * + * * <p>The system maintains a pool of transaction threads in each process that * it runs in. These threads are used to dispatch all * IPCs coming in from other processes. For example, when an IPC is made from @@ -62,7 +62,7 @@ import java.io.FileDescriptor; * thread in process A returns to allow its execution to continue. In effect, * other processes appear to use as additional threads that you did not create * executing in your own process. - * + * * <p>The Binder system also supports recursion across processes. For example * if process A performs a transaction to process B, and process B while * handling that transaction calls transact() on an IBinder that is implemented @@ -70,7 +70,7 @@ import java.io.FileDescriptor; * transaction to finish will take care of calling Binder.onTransact() on the * object being called by B. This ensures that the recursion semantics when * calling remote binder object are the same as when calling local objects. - * + * * <p>When working with remote objects, you often want to find out when they * are no longer valid. There are three ways this can be determined: * <ul> @@ -83,7 +83,7 @@ import java.io.FileDescriptor; * a {@link DeathRecipient} with the IBinder, which will be called when its * containing process goes away. * </ul> - * + * * @see Binder */ public interface IBinder { @@ -95,17 +95,17 @@ public interface IBinder { * The last transaction code available for user commands. */ int LAST_CALL_TRANSACTION = 0x00ffffff; - + /** * IBinder protocol transaction code: pingBinder(). */ int PING_TRANSACTION = ('_'<<24)|('P'<<16)|('N'<<8)|'G'; - + /** * IBinder protocol transaction code: dump internal state. */ int DUMP_TRANSACTION = ('_'<<24)|('D'<<16)|('M'<<8)|'P'; - + /** * IBinder protocol transaction code: execute a shell command. * @hide @@ -129,7 +129,7 @@ public interface IBinder { * across the platform. To support older code, the default implementation * logs the tweet to the main log as a simple emulation of broadcasting * it publicly over the Internet. - * + * * <p>Also, upon completing the dispatch, the object must make a cup * of tea, return it to the caller, and exclaim "jolly good message * old boy!". @@ -142,7 +142,7 @@ public interface IBinder { * its own like counter, and may display this value to the user to indicate the * quality of the app. This is an optional command that applications do not * need to handle, so the default implementation is to do nothing. - * + * * <p>There is no response returned and nothing about the * system will be functionally affected by it, but it will improve the * app's self-esteem. @@ -185,7 +185,8 @@ public interface IBinder { /** * Limit that should be placed on IPC sizes to keep them safely under the - * transaction buffer limit. + * transaction buffer limit. This is a recommendation, and is not the real + * limit. Transactions should be preferred to be even smaller than this. * @hide */ public static final int MAX_IPC_SIZE = 64 * 1024; @@ -206,7 +207,7 @@ public interface IBinder { /** * Check to see if the object still exists. - * + * * @return Returns false if the * hosting process is gone, otherwise the result (always by default * true) returned by the pingBinder() implementation on the other @@ -221,7 +222,7 @@ public interface IBinder { * true, the process may have died while the call is returning. */ public boolean isBinderAlive(); - + /** * Attempt to retrieve a local implementation of an interface * for this Binder object. If null is returned, you will need @@ -232,7 +233,7 @@ public interface IBinder { /** * Print the object's state into the given stream. - * + * * @param fd The raw file descriptor that the dump is being sent to. * @param args additional arguments to the dump request. */ @@ -280,7 +281,7 @@ public interface IBinder { /** * Perform a generic operation with the object. - * + * * @param code The action to perform. This should * be a number between {@link #FIRST_CALL_TRANSACTION} and * {@link #LAST_CALL_TRANSACTION}. @@ -360,13 +361,13 @@ public interface IBinder { * Remove a previously registered death notification. * The recipient will no longer be called if this object * dies. - * + * * @return {@code true} if the <var>recipient</var> is successfully * unlinked, assuring you that its * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method * will not be called; {@code false} if the target IBinder has already * died, meaning the method has been (or soon will be) called. - * + * * @throws java.util.NoSuchElementException if the given * <var>recipient</var> has not been registered with the IBinder, and * the IBinder is still alive. Note that if the <var>recipient</var> diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java index f2143f63d1ee..7b91dd5822e7 100644 --- a/core/java/android/os/ServiceManagerNative.java +++ b/core/java/android/os/ServiceManagerNative.java @@ -50,7 +50,7 @@ public final class ServiceManagerNative { class ServiceManagerProxy implements IServiceManager { public ServiceManagerProxy(IBinder remote) { mRemote = remote; - mServiceManager = IServiceManager.Stub.asInterface(remote); + mServiceManager = IServiceManager.Stub.asInterface(this.getNativeServiceManager()); } public IBinder asBinder() { @@ -128,4 +128,6 @@ class ServiceManagerProxy implements IServiceManager { private IBinder mRemote; private IServiceManager mServiceManager; + + private native IBinder getNativeServiceManager(); } diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java index cba4423831a2..c801fabf9427 100644 --- a/core/java/android/os/SharedMemory.java +++ b/core/java/android/os/SharedMemory.java @@ -25,6 +25,8 @@ import android.system.OsConstants; import dalvik.system.VMRuntime; +import libcore.io.IoUtils; + import java.io.Closeable; import java.io.FileDescriptor; import java.io.IOException; @@ -63,7 +65,7 @@ public final class SharedMemory implements Parcelable, Closeable { mMemoryRegistration = new MemoryRegistration(mSize); mCleaner = Cleaner.create(mFileDescriptor, - new Closer(mFileDescriptor.getInt$(), mMemoryRegistration)); + new Closer(mFileDescriptor, mMemoryRegistration)); } /** @@ -276,7 +278,6 @@ public final class SharedMemory implements Parcelable, Closeable { */ @Override public void close() { - mFileDescriptor.setInt$(-1); if (mCleaner != null) { mCleaner.clean(); mCleaner = null; @@ -326,21 +327,20 @@ public final class SharedMemory implements Parcelable, Closeable { * Cleaner that closes the FD */ private static final class Closer implements Runnable { - private int mFd; + private FileDescriptor mFd; private MemoryRegistration mMemoryReference; - private Closer(int fd, MemoryRegistration memoryReference) { + private Closer(FileDescriptor fd, MemoryRegistration memoryReference) { mFd = fd; + IoUtils.setFdOwner(mFd, this); mMemoryReference = memoryReference; } @Override public void run() { - try { - FileDescriptor fd = new FileDescriptor(); - fd.setInt$(mFd); - Os.close(fd); - } catch (ErrnoException e) { /* swallow error */ } + IoUtils.closeQuietly(mFd); + mFd = null; + mMemoryReference.release(); mMemoryReference = null; } diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index ca694579e9d0..200c1d8edafa 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -68,6 +68,14 @@ flag { } flag { + name: "ordered_broadcast_multiple_permissions" + is_exported: true + namespace: "bluetooth" + description: "Guards the Context.sendOrderedBroadcastMultiplePermissions API" + bug: "345802719" +} + +flag { name: "battery_saver_supported_check_api" namespace: "backstage_power" description: "Guards a new API in PowerManager to check if battery saver is supported or not." diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index aadc8db903eb..5e8d720cc943 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -26,14 +26,6 @@ flag { } flag { - name: "fix_unlocked_device_required_keys_v2" - namespace: "hardware_backed_security" - description: "Fix bugs in behavior of UnlockedDeviceRequired keystore keys" - bug: "296464083" - is_fixed_read_only: true -} - -flag { name: "keyinfo_unlocked_device_required" is_exported: true namespace: "hardware_backed_security" @@ -91,3 +83,10 @@ flag { description: "Add a dump capability for attestation_verification service" bug: "335498868" } + +flag { + name: "should_trust_manager_listen_for_primary_auth" + namespace: "biometrics" + description: "Causes TrustManagerService to listen for credential attempts and ignore reports from upstream" + bug: "323086607" +} diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 327ebd07df1f..c9c2dcc2dd6f 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -536,7 +536,9 @@ public class DreamService extends Service implements Window.Callback { * @see View#findViewById(int) * @see DreamService#requireViewById(int) */ - /* TODO(b/347672184): Re-add @Nullable */ + // Strictly speaking this should be marked as @Nullable but the nullability of the return value + // is deliberately left unspecified as idiomatically correct code can make assumptions either + // way based on local context, e.g. layout specification. public <T extends View> T findViewById(@IdRes int id) { return getWindow().findViewById(id); } diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java index 16d6082649a7..17adb32fb846 100644 --- a/core/java/android/util/StateSet.java +++ b/core/java/android/util/StateSet.java @@ -288,6 +288,9 @@ public class StateSet { case R.attr.state_activated: sb.append("A "); break; + case R.attr.state_hovered: + sb.append("H "); + break; } } diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 9099f9855eab..7eb6f2e2b331 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -284,7 +284,7 @@ public final class PointerIcon implements Parcelable { if (bitmap == null) { throw new IllegalArgumentException("bitmap must not be null"); } - validateHotSpot(bitmap, hotSpotX, hotSpotY); + validateHotSpot(bitmap, hotSpotX, hotSpotY, false /* isScaled */); PointerIcon icon = new PointerIcon(TYPE_CUSTOM); icon.mBitmap = bitmap; @@ -517,7 +517,9 @@ public final class PointerIcon implements Parcelable { BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable); - validateHotSpot(bitmap, hotSpotX, hotSpotY); + // The bitmap and hotspot are loaded from the context, which means it is implicitly scaled + // to the current display density, so treat this as a scaled icon when verifying hotspot. + validateHotSpot(bitmap, hotSpotX, hotSpotY, true /* isScaled */); // Set the properties now that we have successfully loaded the icon. mBitmap = bitmap; mHotSpotX = hotSpotX; @@ -531,11 +533,16 @@ public final class PointerIcon implements Parcelable { + ", hotspotX=" + mHotSpotX + ", hotspotY=" + mHotSpotY + "}"; } - private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) { - if (hotSpotX < 0 || hotSpotX >= bitmap.getWidth()) { + private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY, + boolean isScaled) { + // Be more lenient when checking the hotspot for scaled icons to account for the restriction + // that bitmaps must have an integer size. + if (hotSpotX < 0 || (isScaled ? (int) hotSpotX > bitmap.getWidth() + : hotSpotX >= bitmap.getWidth())) { throw new IllegalArgumentException("x hotspot lies outside of the bitmap area"); } - if (hotSpotY < 0 || hotSpotY >= bitmap.getHeight()) { + if (hotSpotY < 0 || (isScaled ? (int) hotSpotY > bitmap.getHeight() + : hotSpotY >= bitmap.getHeight())) { throw new IllegalArgumentException("y hotspot lies outside of the bitmap area"); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ba6d5df6494b..9aa723aa88e1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -27294,7 +27294,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return a view with given ID if found, or {@code null} otherwise * @see View#requireViewById(int) */ - /* TODO(b/347672184): Re-add @Nullable */ + // Strictly speaking this should be marked as @Nullable but the nullability of the return value + // is deliberately left unspecified as idiomatically correct code can make assumptions either + // way based on local context, e.g. layout specification. public final <T extends View> T findViewById(@IdRes int id) { if (id == NO_ID) { return null; diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index bfdcd5977cd7..50cf5a5fa975 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1712,7 +1712,9 @@ public abstract class Window { * @see View#findViewById(int) * @see Window#requireViewById(int) */ - /* TODO(b/347672184): Re-add @Nullable */ + // Strictly speaking this should be marked as @Nullable but the nullability of the return value + // is deliberately left unspecified as idiomatically correct code can make assumptions either + // way based on local context, e.g. layout specification. public <T extends View> T findViewById(@IdRes int id) { return getDecorView().findViewById(id); } diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS index 898947adcd1b..7f3b4e5a21b3 100644 --- a/core/java/android/view/autofill/OWNERS +++ b/core/java/android/view/autofill/OWNERS @@ -1,10 +1,11 @@ # Bug component: 351486 -simranjit@google.com haoranzhang@google.com +jiewenlei@google.com +simranjit@google.com skxu@google.com +shuc@google.com yunicorn@google.com -reemabajwa@google.com # Bug component: 543785 = per-file *Augmented* per-file *Augmented* = wangqi@google.com diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 82367834f93d..511c6802677e 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -109,4 +109,5 @@ interface ILockSettings { boolean isWeakEscrowTokenActive(long handle, int userId); boolean isWeakEscrowTokenValid(long handle, in byte[] token, int userId); void unlockUserKeyIfUnsecured(int userId); + boolean writeRepairModeCredential(int userId); } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index e46b8d7c5fae..19c6f51ff9a7 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -22,6 +22,8 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; +import static android.security.Flags.reportPrimaryAuthAttempts; +import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth; import android.annotation.IntDef; import android.annotation.NonNull; @@ -414,7 +416,9 @@ public class LockPatternUtils { return; } getDevicePolicyManager().reportFailedPasswordAttempt(userId); - getTrustManager().reportUnlockAttempt(false /* authenticated */, userId); + if (!reportPrimaryAuthAttempts() || !shouldTrustManagerListenForPrimaryAuth()) { + getTrustManager().reportUnlockAttempt(/* authenticated= */ false, userId); + } } @UnsupportedAppUsage @@ -423,7 +427,9 @@ public class LockPatternUtils { return; } getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId); - getTrustManager().reportUnlockAttempt(true /* authenticated */, userId); + if (!reportPrimaryAuthAttempts() || !shouldTrustManagerListenForPrimaryAuth()) { + getTrustManager().reportUnlockAttempt(/* authenticated= */ true, userId); + } } public void reportPasswordLockout(int timeoutMs, int userId) { @@ -449,6 +455,21 @@ public class LockPatternUtils { } /** + * Save the current password data to the repair mode file. + * + * @return true if success or false otherwise. + */ + public boolean writeRepairModeCredential(int userId) { + throwIfCalledOnMainThread(); + try { + return getLockSettings().writeRepairModeCredential(userId); + } catch (RemoteException re) { + Log.e(TAG, "Failed to write repair mode credential", re); + return false; + } + } + + /** * Check to see if a credential matches the saved one. * If credential matches, return an opaque attestation that the challenge was verified. * diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 0734e6827d4d..11c220b14bcc 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -261,6 +261,8 @@ public class LockPatternView extends View { public float lineEndY = Float.MIN_VALUE; @Nullable Animator activationAnimator; + @Nullable + Animator deactivationAnimator; } /** @@ -667,7 +669,7 @@ public class LockPatternView extends View { */ private void resetPattern() { if (mKeepDotActivated && !mPattern.isEmpty()) { - resetLastActivatedCellProgress(); + resetPatternCellSize(); } mPattern.clear(); mPatternPath.reset(); @@ -676,14 +678,20 @@ public class LockPatternView extends View { invalidate(); } - private void resetLastActivatedCellProgress() { - final ArrayList<Cell> pattern = mPattern; - final Cell lastCell = pattern.get(pattern.size() - 1); - final CellState cellState = mCellStates[lastCell.row][lastCell.column]; - if (cellState.activationAnimator != null) { - cellState.activationAnimator.cancel(); + private void resetPatternCellSize() { + for (int i = 0; i < mCellStates.length; i++) { + for (int j = 0; j < mCellStates[i].length; j++) { + CellState cellState = mCellStates[i][j]; + if (cellState.activationAnimator != null) { + cellState.activationAnimator.cancel(); + } + if (cellState.deactivationAnimator != null) { + cellState.deactivationAnimator.cancel(); + } + cellState.activationAnimationProgress = 0f; + cellState.radius = mDotSize / 2f; + } } - cellState.activationAnimationProgress = 0f; } /** @@ -819,12 +827,16 @@ public class LockPatternView extends View { !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) { addCellToPattern(fillInGapCell); if (mKeepDotActivated) { - startCellDeactivatedAnimation(fillInGapCell); + if (mFadePattern) { + startCellDeactivatedAnimation(fillInGapCell, /* fillInGap= */ true); + } else { + startCellActivatedAnimation(fillInGapCell); + } } } if (mKeepDotActivated && lastCell != null) { - startCellDeactivatedAnimation(lastCell); + startCellDeactivatedAnimation(lastCell, /* fillInGap= */ false); } addCellToPattern(cell); @@ -872,17 +884,25 @@ public class LockPatternView extends View { } private void startCellActivatedAnimation(Cell cell) { - startCellActivationAnimation(cell, CELL_ACTIVATE); + startCellActivationAnimation(cell, CELL_ACTIVATE, /* fillInGap= */ false); } - private void startCellDeactivatedAnimation(Cell cell) { - startCellActivationAnimation(cell, CELL_DEACTIVATE); + private void startCellDeactivatedAnimation(Cell cell, boolean fillInGap) { + startCellActivationAnimation(cell, CELL_DEACTIVATE, /* fillInGap= */ fillInGap); } - private void startCellActivationAnimation(Cell cell, int activate) { + /** + * Start cell animation. + * @param cell The cell to be animated. + * @param activate Whether the cell is being activated or deactivated. + * @param fillInGap Whether the cell is a gap cell, i.e. filled in based on current pattern. + */ + private void startCellActivationAnimation(Cell cell, int activate, boolean fillInGap) { final CellState cellState = mCellStates[cell.row][cell.column]; - if (cellState.activationAnimator != null) { + // When mKeepDotActivated is true, don't cancel the previous animator since it would leave + // a dot in an in-between size if the next dot is reached before the animation is finished. + if (cellState.activationAnimator != null && !mKeepDotActivated) { cellState.activationAnimator.cancel(); } AnimatorSet animatorSet = new AnimatorSet(); @@ -898,24 +918,37 @@ public class LockPatternView extends View { .with(createLineEndAnimation(cellState, startX, startY, getCenterXForColumn(cell.column), getCenterYForRow(cell.row))); if (mDotSize != mDotSizeActivated) { - animatorSetBuilder.with(createDotRadiusAnimation(cellState)); + animatorSetBuilder.with(createDotRadiusAnimation(cellState, activate, fillInGap)); } if (mDotColor != mDotActivatedColor) { - animatorSetBuilder.with(createDotActivationColorAnimation(cellState, activate)); + animatorSetBuilder.with( + createDotActivationColorAnimation(cellState, activate, fillInGap)); } - animatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - cellState.activationAnimator = null; - invalidate(); - } - }); - cellState.activationAnimator = animatorSet; + if (activate == CELL_ACTIVATE) { + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + cellState.activationAnimator = null; + invalidate(); + } + }); + cellState.activationAnimator = animatorSet; + } else { + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + cellState.deactivationAnimator = null; + invalidate(); + } + }); + cellState.deactivationAnimator = animatorSet; + } animatorSet.start(); } - private Animator createDotActivationColorAnimation(CellState cellState, int activate) { + private Animator createDotActivationColorAnimation( + CellState cellState, int activate, boolean fillInGap) { ValueAnimator.AnimatorUpdateListener updateListener = valueAnimator -> { cellState.activationAnimationProgress = @@ -934,7 +967,7 @@ public class LockPatternView extends View { deactivateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS); AnimatorSet set = new AnimatorSet(); - if (mKeepDotActivated) { + if (mKeepDotActivated && !fillInGap) { set.play(activate == CELL_ACTIVATE ? activateAnimator : deactivateAnimator); } else { // 'activate' ignored in this case, do full deactivate -> activate cycle @@ -977,7 +1010,7 @@ public class LockPatternView extends View { return valueAnimator; } - private Animator createDotRadiusAnimation(CellState state) { + private Animator createDotRadiusAnimation(CellState state, int activate, boolean fillInGap) { float defaultRadius = mDotSize / 2f; float activatedRadius = mDotSizeActivated / 2f; @@ -998,7 +1031,19 @@ public class LockPatternView extends View { deactivationAnimator.setDuration(DOT_RADIUS_DECREASE_DURATION_MILLIS); AnimatorSet set = new AnimatorSet(); - set.playSequentially(activationAnimator, deactivationAnimator); + if (mKeepDotActivated) { + if (mFadePattern) { + if (fillInGap) { + set.playSequentially(activationAnimator, deactivationAnimator); + } else { + set.play(activate == CELL_ACTIVATE ? activationAnimator : deactivationAnimator); + } + } else if (activate == CELL_ACTIVATE) { + set.play(activationAnimator); + } + } else { + set.playSequentially(activationAnimator, deactivationAnimator); + } return set; } @@ -1176,9 +1221,15 @@ public class LockPatternView extends View { // report pattern detected if (!mPattern.isEmpty()) { setPatternInProgress(false); - cancelLineAnimations(); if (mKeepDotActivated) { + // When mKeepDotActivated is true, cancelling dot animations and resetting dot radii + // are handled in #resetPattern(), since we want to keep the dots activated until + // the pattern are reset. deactivateLastCell(); + } else { + // When mKeepDotActivated is false, cancelling animations and resetting dot radii + // are handled here. + cancelLineAnimations(); } notifyPatternDetected(); // Also clear pattern if fading is enabled @@ -1198,7 +1249,7 @@ public class LockPatternView extends View { private void deactivateLastCell() { Cell lastCell = mPattern.get(mPattern.size() - 1); - startCellDeactivatedAnimation(lastCell); + startCellDeactivatedAnimation(lastCell, /* fillInGap= */ false); } private void cancelLineAnimations() { diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS index e2672f5b03ba..cf2f202a03ac 100644 --- a/core/java/com/android/internal/widget/OWNERS +++ b/core/java/com/android/internal/widget/OWNERS @@ -9,18 +9,18 @@ per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/OWNERS # Notification related -per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS -per-file *Messaging* = file:/services/core/java/com/android/server/notification/OWNERS -per-file *Message* = file:/services/core/java/com/android/server/notification/OWNERS -per-file *Conversation* = file:/services/core/java/com/android/server/notification/OWNERS -per-file *People* = file:/services/core/java/com/android/server/notification/OWNERS -per-file *ImageResolver* = file:/services/core/java/com/android/server/notification/OWNERS -per-file CallLayout.java = file:/services/core/java/com/android/server/notification/OWNERS -per-file CachingIconView.java = file:/services/core/java/com/android/server/notification/OWNERS -per-file ImageFloatingTextView.java = file:/services/core/java/com/android/server/notification/OWNERS -per-file ObservableTextView.java = file:/services/core/java/com/android/server/notification/OWNERS -per-file RemeasuringLinearLayout.java = file:/services/core/java/com/android/server/notification/OWNERS -per-file ViewClippingUtil.java = file:/services/core/java/com/android/server/notification/OWNERS +per-file *Notification* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file *Messaging* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file *Message* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file *Conversation* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file *People* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file *ImageResolver* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file CallLayout.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file CachingIconView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file ImageFloatingTextView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file ObservableTextView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file RemeasuringLinearLayout.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +per-file ViewClippingUtil.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS # Appwidget related per-file *RemoteViews* = file:/services/appwidget/java/com/android/server/appwidget/OWNERS diff --git a/core/jni/Android.bp b/core/jni/Android.bp index f67f1615691e..ce199658c6bf 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -117,6 +117,7 @@ cc_library_shared_for_libandroid_runtime { ], defaults: [ + "aconfig_lib_cc_shared_link.defaults", "latest_android_media_audio_common_types_cpp_target_shared", ], @@ -191,6 +192,7 @@ cc_library_shared_for_libandroid_runtime { "android_os_PerformanceHintManager.cpp", "android_os_SELinux.cpp", "android_os_ServiceManager.cpp", + "android_os_ServiceManagerNative.cpp", "android_os_SharedMemory.cpp", "android_os_storage_StorageManager.cpp", "android_os_UEventObserver.cpp", @@ -361,6 +363,7 @@ cc_library_shared_for_libandroid_runtime { "libdl_android", "libtimeinstate", "server_configurable_flags", + "libaconfig_storage_read_api_cc", "libimage_io", "libultrahdr", "libperfetto_c", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index aa63f4fa03d4..9111129f142d 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -148,6 +148,7 @@ extern int register_android_os_HwParcel(JNIEnv *env); extern int register_android_os_HwRemoteBinder(JNIEnv *env); extern int register_android_os_NativeHandle(JNIEnv *env); extern int register_android_os_ServiceManager(JNIEnv *env); +extern int register_android_os_ServiceManagerNative(JNIEnv* env); extern int register_android_os_MessageQueue(JNIEnv* env); extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_PerformanceHintManager(JNIEnv* env); @@ -1542,6 +1543,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_HwRemoteBinder), REG_JNI(register_android_os_NativeHandle), REG_JNI(register_android_os_ServiceManager), + REG_JNI(register_android_os_ServiceManagerNative), REG_JNI(register_android_os_storage_StorageManager), REG_JNI(register_android_service_DataLoaderService), REG_JNI(register_android_view_DisplayEventReceiver), diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 52237989f059..9fecbd344908 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2703,12 +2703,11 @@ static jint android_media_AudioSystem_getMaxChannelCount(JNIEnv *env, jobject th } 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) + return SAMPLE_RATE_HZ_MAX; } static jint android_media_AudioSystem_getMinSampleRate(JNIEnv *env, jobject thiz) { - return 4000; // SAMPLE_RATE_HZ_MIN (for API) + return SAMPLE_RATE_HZ_MIN; } static std::vector<uid_t> convertJIntArrayToUidVector(JNIEnv *env, jintArray jArray) { diff --git a/core/jni/android_os_ServiceManagerNative.cpp b/core/jni/android_os_ServiceManagerNative.cpp new file mode 100644 index 000000000000..39a3013384ee --- /dev/null +++ b/core/jni/android_os_ServiceManagerNative.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <binder/IServiceManagerFFI.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> + +#include "android_util_Binder.h" +namespace android { + +jobject JNICALL Java_android_os_ServiceManagerProxy_getNativeServiceManager(JNIEnv *env, + jobject obj) { + sp<IBinder> service = IInterface::asBinder( + impl::getJavaServicemanagerImplPrivateDoNotUseExceptInTheOnePlaceItIsUsed()); + return javaObjectForIBinder(env, service); +} + +// ---------------------------------------------------------------------------- + +static const JNINativeMethod serviceManagerNativeMethods[] = { + /* name, signature, funcPtr */ + {"getNativeServiceManager", "()Landroid/os/IBinder;", + (void *)Java_android_os_ServiceManagerProxy_getNativeServiceManager}}; + +int register_android_os_ServiceManagerNative(JNIEnv *env) { + return jniRegisterNativeMethods(env, "android/os/ServiceManagerProxy", + serviceManagerNativeMethods, + NELEM(serviceManagerNativeMethods)); +} +} // namespace android
\ No newline at end of file diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index 67cceb5d5343..581dee571a69 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -185,6 +185,9 @@ https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf --> <shortcode country="it" pattern="\\d{5}" premium="44[0-4]\\d{2}|47[0-4]\\d{2}|48[0-4]\\d{2}|44[5-9]\\d{4}|47[5-9]\\d{4}|48[5-9]\\d{4}|455\\d{2}|499\\d{2}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" /> + <!-- Jordan: 1-5 digits (standard system default, not country specific) --> + <shortcode country="jo" pattern="\\d{1,5}" free="99066" /> + <!-- Japan: 8083 used by SOFTBANK_DCB_2 --> <shortcode country="jp" pattern="\\d{1,5}" free="8083" /> diff --git a/core/tests/coretests/src/android/animation/OWNERS b/core/tests/coretests/src/android/animation/OWNERS new file mode 100644 index 000000000000..1eefb3a3dc65 --- /dev/null +++ b/core/tests/coretests/src/android/animation/OWNERS @@ -0,0 +1 @@ +include /core/java/android/animation/OWNERS diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java index 7b70b412e62b..c8015d43b404 100644 --- a/core/tests/coretests/src/android/content/ContentResolverTest.java +++ b/core/tests/coretests/src/android/content/ContentResolverTest.java @@ -87,7 +87,7 @@ public class ContentResolverTest { bitmap.compress(Bitmap.CompressFormat.PNG, 90, mImage.getOutputStream()); final AssetFileDescriptor afd = new AssetFileDescriptor( - new ParcelFileDescriptor(mImage.getFileDescriptor()), 0, mSize, null); + ParcelFileDescriptor.dup(mImage.getFileDescriptor()), 0, mSize, null); when(mProvider.openTypedAssetFile(any(), any(), any(), any(), any())).thenReturn( afd); } diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java index b90480a1e794..92a7d8ef890d 100644 --- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java @@ -68,6 +68,7 @@ import org.mockito.ArgumentCaptor; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.concurrent.CompletableFuture; @RunWith(AndroidJUnit4.class) @SmallTest @@ -316,6 +317,40 @@ public class LockPatternUtilsTest { assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE); } + @Test + public void testWriteRepairModeCredential_mainThread() { + createTestLockSettings(); + var context = InstrumentationRegistry.getTargetContext(); + + var future = new CompletableFuture<Exception>(); + context.getMainThreadHandler().post(() -> { + try { + mLockPatternUtils.writeRepairModeCredential(USER_ID); + future.complete(null); + } catch (Exception e) { + future.complete(e); + } + }); + + var e = future.join(); + assertThat(e).isNotNull(); + assertThat(e.getMessage()).contains("should not be called from the main thread"); + } + + @Test + public void testWriteRepairModeCredential() throws Exception { + var ils = createTestLockSettings(); + + when(ils.writeRepairModeCredential(USER_ID)).thenReturn(false); + assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse(); + + when(ils.writeRepairModeCredential(USER_ID)).thenReturn(true); + assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isTrue(); + + when(ils.writeRepairModeCredential(USER_ID)).thenThrow(new RemoteException()); + assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse(); + } + private TestStrongAuthTracker createStrongAuthTracker() { final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext()); return new TestStrongAuthTracker(context, Looper.getMainLooper()); diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml index 78c88815b46c..297c490f4819 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="8" + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="18"/> <application android:name="com.android.multidexlegacyandexception.TestApplication" diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml index 1a60c1e45f97..a2082680071a 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="8" + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="18"/> <application android:name=".TestApplication" diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/AndroidManifest.xml index 35369c7da6a1..bb2a20157db9 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/AndroidManifest.xml @@ -4,7 +4,7 @@ android:versionCode="1" android:versionName="1.0" > - <uses-sdk android:minSdkVersion="8" /> + <uses-sdk android:minSdkVersion="21" /> <instrumentation android:name="com.android.test.runner.MultiDexTestRunner" android:targetPackage="com.android.multidexlegacytestapp" /> diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/AndroidManifest.xml index 1cadfcdf3b81..b96566cea3fa 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/AndroidManifest.xml @@ -4,7 +4,7 @@ android:versionCode="1" android:versionName="1.0" > - <uses-sdk android:minSdkVersion="8" /> + <uses-sdk android:minSdkVersion="21" /> <instrumentation android:name="com.android.multidexlegacytestapp.test2.MultiDexAndroidJUnitRunner" android:targetPackage="com.android.multidexlegacytestapp" /> diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/AndroidManifest.xml index e2fba4ef7741..c644c360f3ca 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/AndroidManifest.xml @@ -4,7 +4,7 @@ android:versionCode="1" android:versionName="1.0" > - <uses-sdk android:minSdkVersion="9" /> + <uses-sdk android:minSdkVersion="21" /> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.android.framework.multidexlegacytestservices" /> diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml index 01285e77e3ff..f511c5fca8ce 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml @@ -4,7 +4,7 @@ android:versionCode="1" android:versionName="1.0" > - <uses-sdk android:minSdkVersion="9" /> + <uses-sdk android:minSdkVersion="21" /> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml index 8c911c47dbdf..47302439ef24 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="9" + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="18"/> <application android:name="androidx.multidex.MultiDexApplication" diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml index 1817e952ef7e..0bcf9feb7d1f 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionCode="2" android:versionName="2.0"> - <uses-sdk android:minSdkVersion="9" + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="18"/> <application android:name="androidx.multidex.MultiDexApplication" diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml index c8a41bc43bea..5b7680db9d9b 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml +++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionCode="3" android:versionName="3.0"> - <uses-sdk android:minSdkVersion="9" + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="18"/> <application android:name="androidx.multidex.MultiDexApplication" diff --git a/core/tests/resourceflaggingtests/OWNERS b/core/tests/resourceflaggingtests/OWNERS new file mode 100644 index 000000000000..10950a193b25 --- /dev/null +++ b/core/tests/resourceflaggingtests/OWNERS @@ -0,0 +1 @@ +include /core/java/android/app/RESOURCES_OWNERS diff --git a/data/etc/OWNERS b/data/etc/OWNERS index 701d145fe805..85dae631cac3 100644 --- a/data/etc/OWNERS +++ b/data/etc/OWNERS @@ -1,6 +1,5 @@ include /PACKAGE_MANAGER_OWNERS -alanstokes@google.com cbrubaker@google.com hackbod@android.com hackbod@google.com diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 65615e62c3df..7b96699f7f71 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -325,10 +325,12 @@ <!-- These are the standard packages that are allowed to always have internet access while in power save mode, even if they aren't in the foreground. --> <allow-in-power-save package="com.android.providers.downloads" /> + <allow-in-power-save package="com.android.rkpdapp" /> <!-- These are the standard packages that are allowed to always have internet access while in data mode, even if they aren't in the foreground. --> <allow-in-data-usage-save package="com.android.providers.downloads" /> + <allow-in-data-usage-save package="com.android.rkpdapp" /> <!-- This is a core platform component that needs to freely run in the background --> <allow-in-power-save package="com.android.cellbroadcastreceiver.module" /> diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java index 7c7cb18afc4d..9887c272e7f8 100644 --- a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java +++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java @@ -55,9 +55,9 @@ import com.sun.source.util.TreeScanner; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.tree.JCTree.JCNewClass; import java.util.ArrayList; import java.util.Arrays; @@ -67,7 +67,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Predicate; import java.util.regex.Pattern; import javax.lang.model.element.Name; @@ -125,6 +124,12 @@ public final class RequiresPermissionChecker extends BugChecker instanceMethod() .onDescendantOf("android.content.Context") .withNameMatching(Pattern.compile("^send(Ordered|Sticky)?Broadcast.*$"))); + private static final Matcher<ExpressionTree> SEND_BROADCAST_AS_USER = + methodInvocation( + instanceMethod() + .onDescendantOf("android.content.Context") + .withNameMatching( + Pattern.compile("^send(Ordered|Sticky)?Broadcast.*AsUser.*$"))); private static final Matcher<ExpressionTree> SEND_PENDING_INTENT = methodInvocation( instanceMethod() .onDescendantOf("android.app.PendingIntent") @@ -306,18 +311,6 @@ public final class RequiresPermissionChecker extends BugChecker } } - private static ExpressionTree findArgumentByParameterName(MethodInvocationTree tree, - Predicate<String> paramName) { - final MethodSymbol sym = ASTHelpers.getSymbol(tree); - final List<VarSymbol> params = sym.getParameters(); - for (int i = 0; i < params.size(); i++) { - if (paramName.test(params.get(i).name.toString())) { - return tree.getArguments().get(i); - } - } - return null; - } - private static Name resolveName(ExpressionTree tree) { if (tree instanceof IdentifierTree) { return ((IdentifierTree) tree).getName(); @@ -345,76 +338,85 @@ public final class RequiresPermissionChecker extends BugChecker private static ParsedRequiresPermission parseBroadcastSourceRequiresPermission( MethodInvocationTree methodTree, VisitorState state) { - final ExpressionTree arg = findArgumentByParameterName(methodTree, - (name) -> name.toLowerCase().contains("intent")); - if (arg instanceof IdentifierTree) { - final Name argName = ((IdentifierTree) arg).getName(); - final MethodTree method = state.findEnclosing(MethodTree.class); - final AtomicReference<ParsedRequiresPermission> res = new AtomicReference<>(); - method.accept(new TreeScanner<Void, Void>() { - private ParsedRequiresPermission last; - - @Override - public Void visitMethodInvocation(MethodInvocationTree tree, Void param) { - if (Objects.equal(methodTree, tree)) { - res.set(last); - } else { - final Name name = resolveName(tree.getMethodSelect()); - if (Objects.equal(argName, name) - && INTENT_SET_ACTION.matches(tree, state)) { - last = parseIntentAction(tree); + if (methodTree.getArguments().size() < 1) { + return null; + } + final ExpressionTree arg = methodTree.getArguments().get(0); + if (!(arg instanceof IdentifierTree)) { + return null; + } + final Name argName = ((IdentifierTree) arg).getName(); + final MethodTree method = state.findEnclosing(MethodTree.class); + final AtomicReference<ParsedRequiresPermission> res = new AtomicReference<>(); + method.accept(new TreeScanner<Void, Void>() { + private ParsedRequiresPermission mLast; + + @Override + public Void visitMethodInvocation(MethodInvocationTree tree, Void param) { + if (Objects.equal(methodTree, tree)) { + res.set(mLast); + } else { + final Name name = resolveName(tree.getMethodSelect()); + if (Objects.equal(argName, name) && INTENT_SET_ACTION.matches(tree, state)) { + mLast = parseIntentAction(tree); + } else if (name == null && tree.getMethodSelect() instanceof MemberSelectTree) { + ExpressionTree innerTree = + ((MemberSelectTree) tree.getMethodSelect()).getExpression(); + if (innerTree instanceof JCNewClass) { + mLast = parseIntentAction((NewClassTree) innerTree); } } - return super.visitMethodInvocation(tree, param); } + return super.visitMethodInvocation(tree, param); + } - @Override - public Void visitAssignment(AssignmentTree tree, Void param) { - final Name name = resolveName(tree.getVariable()); - final Tree init = tree.getExpression(); - if (Objects.equal(argName, name) - && init instanceof NewClassTree) { - last = parseIntentAction((NewClassTree) init); - } - return super.visitAssignment(tree, param); + @Override + public Void visitAssignment(AssignmentTree tree, Void param) { + final Name name = resolveName(tree.getVariable()); + final Tree init = tree.getExpression(); + if (Objects.equal(argName, name) && init instanceof NewClassTree) { + mLast = parseIntentAction((NewClassTree) init); } + return super.visitAssignment(tree, param); + } - @Override - public Void visitVariable(VariableTree tree, Void param) { - final Name name = tree.getName(); - final ExpressionTree init = tree.getInitializer(); - if (Objects.equal(argName, name) - && init instanceof NewClassTree) { - last = parseIntentAction((NewClassTree) init); - } - return super.visitVariable(tree, param); + @Override + public Void visitVariable(VariableTree tree, Void param) { + final Name name = tree.getName(); + final ExpressionTree init = tree.getInitializer(); + if (Objects.equal(argName, name) && init instanceof NewClassTree) { + mLast = parseIntentAction((NewClassTree) init); } - }, null); - return res.get(); - } - return null; + return super.visitVariable(tree, param); + } + }, null); + return res.get(); } private static ParsedRequiresPermission parseBroadcastTargetRequiresPermission( MethodInvocationTree tree, VisitorState state) { - final ExpressionTree arg = findArgumentByParameterName(tree, - (name) -> name.toLowerCase().contains("permission")); final ParsedRequiresPermission res = new ParsedRequiresPermission(); - if (arg != null) { - arg.accept(new TreeScanner<Void, Void>() { - @Override - public Void visitIdentifier(IdentifierTree tree, Void param) { - res.addConstValue(tree); - return super.visitIdentifier(tree, param); - } - - @Override - public Void visitMemberSelect(MemberSelectTree tree, Void param) { - res.addConstValue(tree); - return super.visitMemberSelect(tree, param); - } - }, null); + int permission_position = 1; + if (SEND_BROADCAST_AS_USER.matches(tree, state)) { + permission_position = 2; } + if (tree.getArguments().size() < permission_position + 1) { + return res; + } + final ExpressionTree arg = tree.getArguments().get(permission_position); + arg.accept(new TreeScanner<Void, Void>() { + @Override + public Void visitIdentifier(IdentifierTree tree, Void param) { + res.addConstValue(tree); + return super.visitIdentifier(tree, param); + } + + @Override + public Void visitMemberSelect(MemberSelectTree tree, Void param) { + res.addConstValue(tree); + return super.visitMemberSelect(tree, param); + } + }, null); return res; } diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java index e53372d97f3d..05fde7c4fe57 100644 --- a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java +++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java @@ -412,6 +412,19 @@ public class RequiresPermissionCheckerTest { " context.sendBroadcast(intent);", " }", " }", + " public void exampleWithChainedMethod(Context context) {", + " Intent intent = new Intent(FooManager.ACTION_RED)", + " .putExtra(\"foo\", 42);", + " context.sendBroadcast(intent, FooManager.PERMISSION_RED);", + " context.sendBroadcastWithMultiplePermissions(intent,", + " new String[] { FooManager.PERMISSION_RED });", + " }", + " public void exampleWithAsUser(Context context) {", + " Intent intent = new Intent(FooManager.ACTION_RED);", + " context.sendBroadcastAsUser(intent, 42, FooManager.PERMISSION_RED);", + " context.sendBroadcastAsUserMultiplePermissions(intent, 42,", + " new String[] { FooManager.PERMISSION_RED });", + " }", "}") .doTest(); } diff --git a/errorprone/tests/res/android/content/Context.java b/errorprone/tests/res/android/content/Context.java index efc4fb122435..9d622ffaf120 100644 --- a/errorprone/tests/res/android/content/Context.java +++ b/errorprone/tests/res/android/content/Context.java @@ -36,4 +36,15 @@ public class Context { public void sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions) { throw new UnsupportedOperationException(); } + + /* Fake user type for test purposes */ + public void sendBroadcastAsUser(Intent intent, int user, String receiverPermission) { + throw new UnsupportedOperationException(); + } + + /* Fake user type for test purposes */ + public void sendBroadcastAsUserMultiplePermissions( + Intent intent, int user, String[] receiverPermissions) { + throw new UnsupportedOperationException(); + } } diff --git a/errorprone/tests/res/android/content/Intent.java b/errorprone/tests/res/android/content/Intent.java index 288396e60577..7ccea784754a 100644 --- a/errorprone/tests/res/android/content/Intent.java +++ b/errorprone/tests/res/android/content/Intent.java @@ -24,4 +24,8 @@ public class Intent { public Intent setAction(String action) { throw new UnsupportedOperationException(); } + + public Intent putExtra(String extra, int value) { + throw new UnsupportedOperationException(); + } } diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 4b367e0e5b4b..f9fd3694835e 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -66,6 +66,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import javax.security.auth.x500.X500Principal; @@ -376,6 +377,8 @@ public final class KeyChain { */ public static final int KEY_ATTESTATION_FAILURE = 4; + private static final int BIND_KEY_CHAIN_SERVICE_TIMEOUT_MS = 30 * 1000; + /** * Used by DPC or delegated app in * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias} or @@ -1120,7 +1123,10 @@ public final class KeyChain { context.unbindService(keyChainServiceConnection); throw new AssertionError("could not bind to KeyChainService"); } - countDownLatch.await(); + if (!countDownLatch.await(BIND_KEY_CHAIN_SERVICE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + context.unbindService(keyChainServiceConnection); + throw new AssertionError("binding to KeyChainService timeout"); + } IKeyChainService service = keyChainService.get(); if (service != null) { return new KeyChainConnection(context, keyChainServiceConnection, service); diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS index ebebd8a52c9a..cb422eab372b 100644 --- a/libs/WindowManager/Shell/OWNERS +++ b/libs/WindowManager/Shell/OWNERS @@ -1,5 +1,5 @@ xutan@google.com # Give submodule owners in shell resource approval -per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com +per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com per-file res*/*/tv_*.xml = bronger@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS new file mode 100644 index 000000000000..482aaab6bc74 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS @@ -0,0 +1 @@ +per-file KtProtolog.kt = file:platform/development:/tools/winscope/OWNERS diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS index 0f24bb549158..2a0a28ebcaa2 100644 --- a/libs/WindowManager/Shell/tests/OWNERS +++ b/libs/WindowManager/Shell/tests/OWNERS @@ -9,7 +9,7 @@ hwwang@google.com chenghsiuchang@google.com atsjenk@google.com jorgegil@google.com -nmusgrave@google.com +vaniadesmonda@google.com pbdr@google.com tkachenkoi@google.com mpodolian@google.com diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp index b68143d82090..94351182871a 100644 --- a/libs/androidfw/LocaleDataTables.cpp +++ b/libs/androidfw/LocaleDataTables.cpp @@ -2451,10 +2451,10 @@ const struct { const char script[4]; const std::unordered_map<uint32_t, uint32_t>* map; } SCRIPT_PARENTS[] = { + {{'L', 'a', 't', 'n'}, &LATN_PARENTS}, {{'A', 'r', 'a', 'b'}, &ARAB_PARENTS}, {{'D', 'e', 'v', 'a'}, &DEVA_PARENTS}, {{'H', 'a', 'n', 't'}, &HANT_PARENTS}, - {{'L', 'a', 't', 'n'}, &LATN_PARENTS}, {{'~', '~', '~', 'B'}, &___B_PARENTS}, }; diff --git a/location/Android.bp b/location/Android.bp index 5ba35ac3328a..10ca97d74660 100644 --- a/location/Android.bp +++ b/location/Android.bp @@ -30,15 +30,17 @@ java_sdk_library { "app-compat-annotations", "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage ], - hidden_api_packages: [ - "com.android.internal.location", - ], aidl: { include_dirs: [ "frameworks/base/location/java", "frameworks/base/core/java", ], }, + lint: { + warning_checks: [ + "FlaggedApi", + ], + }, } platform_compat_config { diff --git a/location/java/com/android/internal/location/package-info.java b/location/java/com/android/internal/location/package-info.java new file mode 100644 index 000000000000..25573c15ce59 --- /dev/null +++ b/location/java/com/android/internal/location/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Exclude from API surfaces + * + * @hide + */ +package com.android.internal.location; diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 293c561f166c..47adde49b86e 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -1636,7 +1636,8 @@ public class AudioSystem /** @hide */ public static final int FORCE_ENCODED_SURROUND_NEVER = 13; /** @hide */ public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14; /** @hide */ public static final int FORCE_ENCODED_SURROUND_MANUAL = 15; - /** @hide */ public static final int NUM_FORCE_CONFIG = 16; + /** @hide */ public static final int FORCE_BT_BLE = 16; + /** @hide */ public static final int NUM_FORCE_CONFIG = 17; /** @hide */ public static final int FORCE_DEFAULT = FORCE_NONE; /** @hide */ @@ -1658,6 +1659,7 @@ public class AudioSystem case FORCE_ENCODED_SURROUND_NEVER: return "FORCE_ENCODED_SURROUND_NEVER"; case FORCE_ENCODED_SURROUND_ALWAYS: return "FORCE_ENCODED_SURROUND_ALWAYS"; case FORCE_ENCODED_SURROUND_MANUAL: return "FORCE_ENCODED_SURROUND_MANUAL"; + case FORCE_BT_BLE: return "FORCE_BT_BLE"; default: return "unknown config (" + config + ")" ; } } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 3ba0d599fde8..8acaf3be5152 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -5143,9 +5143,9 @@ final public class MediaCodec { * of negative QP and positive QP are chosen wisely, the overall viewing experience can be * improved. * <p> - * If byte array size is too small than the expected size, components may ignore the - * configuration silently. If the byte array exceeds the expected size, components shall use - * the initial portion and ignore the rest. + * If byte array size is smaller than the expected size, components will ignore the + * configuration and print an error message. If the byte array exceeds the expected size, + * components will use the initial portion and ignore the rest. * <p> * The scope of this key is throughout the encoding session until it is reconfigured during * running state. @@ -5159,7 +5159,8 @@ final public class MediaCodec { * Set the region of interest as QpOffset-Rects on the next queued input frame. * <p> * The associated value is a String in the format "Top1,Left1-Bottom1,Right1=Offset1;Top2, - * Left2-Bottom2,Right2=Offset2;...". Co-ordinates (Top, Left), (Top, Right), (Bottom, Left) + * Left2-Bottom2,Right2=Offset2;...". If the configuration doesn't follow this pattern, + * it will be ignored. Co-ordinates (Top, Left), (Top, Right), (Bottom, Left) * and (Bottom, Right) form the vertices of bounding box of region of interest in pixels. * Pixel (0, 0) points to the top-left corner of the frame. Offset is the suggested * quantization parameter (QP) offset of the blocks in the bounding box. The bounding box @@ -5171,9 +5172,10 @@ final public class MediaCodec { * negative QP and positive QP are chosen wisely, the overall viewing experience can be * improved. * <p> - * If Roi rect is not valid that is bounding box width is < 0 or bounding box height is < 0, - * components may ignore the configuration silently. If Roi rect extends outside frame - * boundaries, then rect shall be clamped to the frame boundaries. + * If roi (region of interest) rect is outside the frame boundaries, that is, left < 0 or + * top < 0 or right > width or bottom > height, then rect shall be clamped to the frame + * boundaries. If roi rect is not valid, that is left > right or top > bottom, then the + * parameter setting is ignored. * <p> * The scope of this key is throughout the encoding session until it is reconfigured during * running state. diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 21415166d4ed..1ed6476fb7d0 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -79,7 +79,6 @@ cc_library_shared { "libcamera_client", "libmtp", "libpiex", - "libprocessgroup", "libandroidfw", "libhidlallocatorutils", "libhidlbase", diff --git a/media/tests/SoundPoolTest/AndroidManifest.xml b/media/tests/SoundPoolTest/AndroidManifest.xml index c18efa29462c..b24639ca2d63 100644 --- a/media/tests/SoundPoolTest/AndroidManifest.xml +++ b/media/tests/SoundPoolTest/AndroidManifest.xml @@ -12,6 +12,6 @@ </intent-filter> </activity> </application> - <uses-sdk android:minSdkVersion="8" + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="8"/> </manifest> diff --git a/nfc/Android.bp b/nfc/Android.bp index 421f06d5cf2b..2a01b3fec088 100644 --- a/nfc/Android.bp +++ b/nfc/Android.bp @@ -59,9 +59,6 @@ java_sdk_library { "android.nfc", "com.android.nfc", ], - hidden_api_packages: [ - "com.android.nfc", - ], impl_library_visibility: [ "//frameworks/base:__subpackages__", "//cts/tests/tests/nfc", diff --git a/packages/CrashRecovery/aconfig/flags.aconfig b/packages/CrashRecovery/aconfig/flags.aconfig index 80412321d60b..225f8c685fe1 100644 --- a/packages/CrashRecovery/aconfig/flags.aconfig +++ b/packages/CrashRecovery/aconfig/flags.aconfig @@ -26,8 +26,8 @@ flag { } flag { - name: "reenable_settings_resets" + name: "deprecate_flags_and_settings_resets" namespace: "modularization" - description: "Re-enables settings resets only, deletes flag resets" + description: "Deletes flag and settings resets" bug: "333847376" } diff --git a/packages/CtsShim/Android.bp b/packages/CtsShim/Android.bp index baafe7ba570c..a94c8c56a31f 100644 --- a/packages/CtsShim/Android.bp +++ b/packages/CtsShim/Android.bp @@ -61,7 +61,6 @@ android_app_import { "com.android.apex.cts.shim.v1", "com.android.apex.cts.shim.v2", "com.android.apex.cts.shim.v2_legacy", - "com.android.apex.cts.shim.v2_no_hashtree", "com.android.apex.cts.shim.v2_sdk_target_p", "com.android.apex.cts.shim.v3", ], @@ -102,7 +101,6 @@ android_app_import { "com.android.apex.cts.shim.v1", "com.android.apex.cts.shim.v2", "com.android.apex.cts.shim.v2_legacy", - "com.android.apex.cts.shim.v2_no_hashtree", "com.android.apex.cts.shim.v2_sdk_target_p", "com.android.apex.cts.shim.v3", ], diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp index d6b7ecf5819d..5b3d47e9f74d 100644 --- a/packages/CtsShim/build/Android.bp +++ b/packages/CtsShim/build/Android.bp @@ -93,7 +93,6 @@ android_app { "com.android.apex.cts.shim.v1", "com.android.apex.cts.shim.v2", "com.android.apex.cts.shim.v2_apk_in_apex_upgrades", - "com.android.apex.cts.shim.v2_no_hashtree", "com.android.apex.cts.shim.v2_legacy", "com.android.apex.cts.shim.v2_sdk_target_p", "com.android.apex.cts.shim.v2_unsigned_payload", @@ -200,7 +199,6 @@ android_app { "com.android.apex.cts.shim.v1", "com.android.apex.cts.shim.v2", "com.android.apex.cts.shim.v2_apk_in_apex_upgrades", - "com.android.apex.cts.shim.v2_no_hashtree", "com.android.apex.cts.shim.v2_legacy", "com.android.apex.cts.shim.v2_sdk_target_p", "com.android.apex.cts.shim.v2_unsigned_payload", diff --git a/packages/CtsShim/build/jni/Android.bp b/packages/CtsShim/build/jni/Android.bp index 2dbf2a212cc3..ac85d2b60327 100644 --- a/packages/CtsShim/build/jni/Android.bp +++ b/packages/CtsShim/build/jni/Android.bp @@ -33,7 +33,6 @@ cc_library_shared { "com.android.apex.cts.shim.v1", "com.android.apex.cts.shim.v2", "com.android.apex.cts.shim.v2_apk_in_apex_upgrades", - "com.android.apex.cts.shim.v2_no_hashtree", "com.android.apex.cts.shim.v2_legacy", "com.android.apex.cts.shim.v2_sdk_target_p", "com.android.apex.cts.shim.v2_unsigned_payload", diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS index 7669e79b42be..f8c3a93cd3c7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS @@ -1,9 +1,4 @@ # Default reviewers for this and subdirectories. -siyuanh@google.com -hughchen@google.com -timhypeng@google.com -robertluo@google.com -songferngwang@google.com yqian@google.com chelseahao@google.com yiyishen@google.com diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java index 8dd51b2b8d11..8de0c35ffa12 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java @@ -22,8 +22,6 @@ import static junit.framework.Assert.assertNull; import android.content.ContentResolver; import android.os.Bundle; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; @@ -73,24 +71,9 @@ public class DeviceConfigServiceTest { } /** - * Test that setting overrides are properly disabled when the flag is off. - */ - @Test - @RequiresFlagsDisabled("com.android.providers.settings.support_overrides") - public void testOverrideDisabled() throws IOException { - final String newValue = "value2"; - - executeShellCommand("device_config put " + sNamespace + " " + sKey + " " + sValue); - executeShellCommand("device_config override " + sNamespace + " " + sKey + " " + newValue); - String result = readShellCommandOutput("device_config get " + sNamespace + " " + sKey); - assertEquals(sValue + "\n", result); - } - - /** * Test that overrides are readable and can be cleared. */ @Test - @RequiresFlagsEnabled("com.android.providers.settings.support_overrides") public void testOverride() throws IOException { final String newValue = "value2"; diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index 3a5ec92fc335..9374bf4dcdff 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -8,6 +8,7 @@ achalke@google.com acul@google.com adamcohen@google.com aioana@google.com +alexchau@google.com alexflo@google.com andonian@google.com aroederer@google.com @@ -83,8 +84,10 @@ princedonkor@google.com rahulbanerjee@google.com roosa@google.com saff@google.com +samcackett@google.com santie@google.com shanh@google.com +silvajordan@google.com snoeberger@google.com steell@google.com stevenckng@google.com @@ -96,6 +99,7 @@ tkachenkoi@google.com tracyzhou@google.com tsuji@google.com twickham@google.com +uwaisashraf@google.com vadimt@google.com valiiftime@google.com vanjan@google.com diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt index beb8ddef949d..24cbd1036770 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt @@ -264,7 +264,7 @@ fun LazyGridItemScope.DraggableItem( alpha = itemAlpha } } else { - Modifier.animateItemPlacement() + Modifier.animateItem() } Box(modifier) { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java index b4530ace68d6..ed7062b5a335 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java @@ -26,6 +26,7 @@ import android.content.res.Configuration; import android.util.Range; import android.view.WindowManager; +import com.android.internal.accessibility.common.MagnificationConstants; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.util.settings.SecureSettings; @@ -40,7 +41,8 @@ import com.android.systemui.util.settings.SecureSettings; public class MagnificationSettingsController implements ComponentCallbacks { // It should be consistent with the value defined in WindowMagnificationGestureHandler. - private static final Range<Float> A11Y_ACTION_SCALE_RANGE = new Range<>(1.0f, 8.0f); + private static final Range<Float> A11Y_ACTION_SCALE_RANGE = + new Range<>(1.0f, MagnificationConstants.SCALE_MAX_VALUE); private final Context mContext; diff --git a/services/Android.bp b/services/Android.bp index 0fbbd16b1ed9..a0d345430a4a 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -239,6 +239,7 @@ java_library { libs: [ "android.hidl.manager-V1.0-java", "framework-tethering.stubs.module_lib", + "keepanno-annotations", "service-art.stubs.system_server", "service-permission.stubs.system_server", "service-rkp.stubs.system_server", diff --git a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java index e6055148867d..2009cd3d4527 100644 --- a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java +++ b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java @@ -659,6 +659,8 @@ class FlashNotificationsController { mIsTorchTouched = on; } catch (CameraAccessException e) { Log.e(LOG_TAG, "Failed to setTorchMode: " + e); + } catch (IllegalArgumentException e) { + Log.e(LOG_TAG, "Failed to setTorchMode: " + e); } } else { Log.e(LOG_TAG, "Can not use camera flash notification, please check CameraManager!"); diff --git a/services/core/Android.bp b/services/core/Android.bp index 7fb22500d295..fa323fd04837 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -182,6 +182,7 @@ java_library_static { "android.hardware.vibrator-V2-java", "app-compat-annotations", "framework-tethering.stubs.module_lib", + "keepanno-annotations", "service-art.stubs.system_server", "service-permission.stubs.system_server", "service-rkp.stubs.system_server", @@ -267,6 +268,9 @@ java_library_static { ], lint: { baseline_filename: "lint-baseline.xml", + warning_checks: [ + "FlaggedApi", + ], }, } diff --git a/services/core/java/com/android/server/CertBlacklister.java b/services/core/java/com/android/server/CertBlocklister.java index e726c6abfac3..9e23f884f4ba 100644 --- a/services/core/java/com/android/server/CertBlacklister.java +++ b/services/core/java/com/android/server/CertBlocklister.java @@ -16,37 +16,39 @@ package com.android.server; -import android.content.Context; import android.content.ContentResolver; +import android.content.Context; import android.database.ContentObserver; import android.os.Binder; import android.os.FileUtils; import android.provider.Settings; import android.util.Slog; +import libcore.io.IoUtils; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import libcore.io.IoUtils; - /** - * <p>CertBlacklister provides a simple mechanism for updating the platform denylists for SSL + * <p>CertBlocklister provides a simple mechanism for updating the platform denylists for SSL * certificate public keys and serial numbers. */ -public class CertBlacklister extends Binder { +public class CertBlocklister extends Binder { - private static final String TAG = "CertBlacklister"; + private static final String TAG = "CertBlocklister"; private static final String DENYLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/"; + /* For compatibility reasons, the name of these paths cannot be changed */ public static final String PUBKEY_PATH = DENYLIST_ROOT + "pubkey_blacklist.txt"; public static final String SERIAL_PATH = DENYLIST_ROOT + "serial_blacklist.txt"; - public static final String PUBKEY_BLACKLIST_KEY = "pubkey_blacklist"; - public static final String SERIAL_BLACKLIST_KEY = "serial_blacklist"; + /* For compatibility reasons, the name of these keys cannot be changed */ + public static final String PUBKEY_BLOCKLIST_KEY = "pubkey_blacklist"; + public static final String SERIAL_BLOCKLIST_KEY = "serial_blacklist"; - private static class BlacklistObserver extends ContentObserver { + private static class BlocklistObserver extends ContentObserver { private final String mKey; private final String mName; @@ -54,7 +56,7 @@ public class CertBlacklister extends Binder { private final File mTmpDir; private final ContentResolver mContentResolver; - public BlacklistObserver(String key, String name, String path, ContentResolver cr) { + BlocklistObserver(String key, String name, String path, ContentResolver cr) { super(null); mKey = key; mName = name; @@ -66,59 +68,61 @@ public class CertBlacklister extends Binder { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - writeDenylist(); + new Thread("BlocklistUpdater") { + public void run() { + writeDenylist(); + } + }.start(); } public String getValue() { - return Settings.Secure.getString(mContentResolver, mKey); + return Settings.Secure.getStringForUser( + mContentResolver, mKey, mContentResolver.getUserId()); } private void writeDenylist() { - new Thread("BlacklistUpdater") { - public void run() { - synchronized(mTmpDir) { - String blacklist = getValue(); - if (blacklist != null) { - Slog.i(TAG, "Certificate blacklist changed, updating..."); - FileOutputStream out = null; - try { - // create a temporary file - File tmp = File.createTempFile("journal", "", mTmpDir); - // mark it -rw-r--r-- - tmp.setReadable(true, false); - // write to it - out = new FileOutputStream(tmp); - out.write(blacklist.getBytes()); - // sync to disk - FileUtils.sync(out); - // atomic rename - tmp.renameTo(new File(mPath)); - Slog.i(TAG, "Certificate blacklist updated"); - } catch (IOException e) { - Slog.e(TAG, "Failed to write blacklist", e); - } finally { - IoUtils.closeQuietly(out); - } - } - } + synchronized (mTmpDir) { + String blocklist = getValue(); + if (blocklist == null) { + return; } - }.start(); + if (mPath.equals(SERIAL_PATH)) { + Slog.w(TAG, "The certificate blocklist based on serials is deprecated. " + + "Please use the pubkey blocklist instead."); + } + Slog.i(TAG, "Certificate blocklist changed, updating..."); + FileOutputStream out = null; + try { + // Create a temporary file and rename it atomically. + File tmp = File.createTempFile("journal", "", mTmpDir); + tmp.setReadable(true /* readable */, false /* ownerOnly */); + out = new FileOutputStream(tmp); + out.write(blocklist.getBytes()); + FileUtils.sync(out); + tmp.renameTo(new File(mPath)); + Slog.i(TAG, "Certificate blocklist updated"); + } catch (IOException e) { + Slog.e(TAG, "Failed to write blocklist", e); + } finally { + IoUtils.closeQuietly(out); + } + } } } - public CertBlacklister(Context context) { + public CertBlocklister(Context context) { registerObservers(context.getContentResolver()); } - private BlacklistObserver buildPubkeyObserver(ContentResolver cr) { - return new BlacklistObserver(PUBKEY_BLACKLIST_KEY, + private BlocklistObserver buildPubkeyObserver(ContentResolver cr) { + return new BlocklistObserver(PUBKEY_BLOCKLIST_KEY, "pubkey", PUBKEY_PATH, cr); } - private BlacklistObserver buildSerialObserver(ContentResolver cr) { - return new BlacklistObserver(SERIAL_BLACKLIST_KEY, + private BlocklistObserver buildSerialObserver(ContentResolver cr) { + return new BlocklistObserver(SERIAL_BLOCKLIST_KEY, "serial", SERIAL_PATH, cr); @@ -127,16 +131,16 @@ public class CertBlacklister extends Binder { private void registerObservers(ContentResolver cr) { // set up the public key denylist observer cr.registerContentObserver( - Settings.Secure.getUriFor(PUBKEY_BLACKLIST_KEY), - true, - buildPubkeyObserver(cr) + Settings.Secure.getUriFor(PUBKEY_BLOCKLIST_KEY), + true, + buildPubkeyObserver(cr) ); // set up the serial number denylist observer cr.registerContentObserver( - Settings.Secure.getUriFor(SERIAL_BLACKLIST_KEY), - true, - buildSerialObserver(cr) + Settings.Secure.getUriFor(SERIAL_BLOCKLIST_KEY), + true, + buildSerialObserver(cr) ); } } diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 2545620a2630..a627a3967802 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -48,3 +48,6 @@ per-file VcnManagementService.java = file:/services/core/java/com/android/server # SystemConfig per-file SystemConfig.java = file:/PACKAGE_MANAGER_OWNERS + +# CertBlocklister +per-file Cert*.java = tweek@google.com, brambonne@google.com, prb@google.com, miguelaranda@google.com diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index 189b2495c1b1..c2cb5e90ca58 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -58,7 +58,6 @@ import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -242,12 +241,14 @@ public class RescueParty { * opportunity to reset any settings depending on our rescue level. */ public static void onSettingsProviderPublished(Context context) { - handleNativeRescuePartyResets(); - ContentResolver contentResolver = context.getContentResolver(); - DeviceConfig.setMonitorCallback( - contentResolver, - Executors.newSingleThreadExecutor(), - new RescuePartyMonitorCallback(context)); + if (!Flags.deprecateFlagsAndSettingsResets()) { + handleNativeRescuePartyResets(); + ContentResolver contentResolver = context.getContentResolver(); + DeviceConfig.setMonitorCallback( + contentResolver, + Executors.newSingleThreadExecutor(), + new RescuePartyMonitorCallback(context)); + } } @@ -257,75 +258,81 @@ public class RescueParty { * on modules of newer versions. */ public static void resetDeviceConfigForPackages(List<String> packageNames) { - if (packageNames == null) { - return; - } - Set<String> namespacesToReset = new ArraySet<String>(); - Iterator<String> it = packageNames.iterator(); - RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstanceIfCreated(); - // Get runtime package to namespace mapping if created. - if (rescuePartyObserver != null) { - while (it.hasNext()) { - String packageName = it.next(); - Set<String> runtimeAffectedNamespaces = - rescuePartyObserver.getAffectedNamespaceSet(packageName); - if (runtimeAffectedNamespaces != null) { - namespacesToReset.addAll(runtimeAffectedNamespaces); + if (!Flags.deprecateFlagsAndSettingsResets()) { + if (packageNames == null) { + return; + } + Set<String> namespacesToReset = new ArraySet<String>(); + Iterator<String> it = packageNames.iterator(); + RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstanceIfCreated(); + // Get runtime package to namespace mapping if created. + if (rescuePartyObserver != null) { + while (it.hasNext()) { + String packageName = it.next(); + Set<String> runtimeAffectedNamespaces = + rescuePartyObserver.getAffectedNamespaceSet(packageName); + if (runtimeAffectedNamespaces != null) { + namespacesToReset.addAll(runtimeAffectedNamespaces); + } } } - } - // Get preset package to namespace mapping if created. - Set<String> presetAffectedNamespaces = getPresetNamespacesForPackages( - packageNames); - if (presetAffectedNamespaces != null) { - namespacesToReset.addAll(presetAffectedNamespaces); - } + // Get preset package to namespace mapping if created. + Set<String> presetAffectedNamespaces = getPresetNamespacesForPackages( + packageNames); + if (presetAffectedNamespaces != null) { + namespacesToReset.addAll(presetAffectedNamespaces); + } - // Clear flags under the namespaces mapped to these packages. - // Using setProperties since DeviceConfig.resetToDefaults bans the current flag set. - Iterator<String> namespaceIt = namespacesToReset.iterator(); - while (namespaceIt.hasNext()) { - String namespaceToReset = namespaceIt.next(); - Properties properties = new Properties.Builder(namespaceToReset).build(); - try { - if (!DeviceConfig.setProperties(properties)) { - logCriticalInfo(Log.ERROR, "Failed to clear properties under " + // Clear flags under the namespaces mapped to these packages. + // Using setProperties since DeviceConfig.resetToDefaults bans the current flag set. + Iterator<String> namespaceIt = namespacesToReset.iterator(); + while (namespaceIt.hasNext()) { + String namespaceToReset = namespaceIt.next(); + Properties properties = new Properties.Builder(namespaceToReset).build(); + try { + if (!DeviceConfig.setProperties(properties)) { + logCriticalInfo(Log.ERROR, "Failed to clear properties under " + namespaceToReset + ". Running `device_config get_sync_disabled_for_tests` will confirm" + " if config-bulk-update is enabled."); + } + } catch (DeviceConfig.BadConfigException exception) { + logCriticalInfo(Log.WARN, "namespace " + namespaceToReset + + " is already banned, skip reset."); } - } catch (DeviceConfig.BadConfigException exception) { - logCriticalInfo(Log.WARN, "namespace " + namespaceToReset - + " is already banned, skip reset."); } } } private static Set<String> getPresetNamespacesForPackages(List<String> packageNames) { Set<String> resultSet = new ArraySet<String>(); - try { - String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION, - NAMESPACE_TO_PACKAGE_MAPPING_FLAG, ""); - String[] mappingEntries = flagVal.split(","); - for (int i = 0; i < mappingEntries.length; i++) { - if (TextUtils.isEmpty(mappingEntries[i])) { - continue; - } - String[] splittedEntry = mappingEntries[i].split(":"); - if (splittedEntry.length != 2) { - throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]); - } - String namespace = splittedEntry[0]; - String packageName = splittedEntry[1]; + if (!Flags.deprecateFlagsAndSettingsResets()) { + try { + String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION, + NAMESPACE_TO_PACKAGE_MAPPING_FLAG, ""); + String[] mappingEntries = flagVal.split(","); + for (int i = 0; i < mappingEntries.length; i++) { + if (TextUtils.isEmpty(mappingEntries[i])) { + continue; + } + String[] splitEntry = mappingEntries[i].split(":"); + if (splitEntry.length != 2) { + throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]); + } + String namespace = splitEntry[0]; + String packageName = splitEntry[1]; - if (packageNames.contains(packageName)) { - resultSet.add(namespace); + if (packageNames.contains(packageName)) { + resultSet.add(namespace); + } } + } catch (Exception e) { + resultSet.clear(); + Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e); + } finally { + return resultSet; } - } catch (Exception e) { - resultSet.clear(); - Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e); - } finally { + } else { return resultSet; } } @@ -343,43 +350,54 @@ public class RescueParty { } public void onNamespaceUpdate(@NonNull String updatedNamespace) { - startObservingPackages(mContext, updatedNamespace); + if (!Flags.deprecateFlagsAndSettingsResets()) { + startObservingPackages(mContext, updatedNamespace); + } } public void onDeviceConfigAccess(@NonNull String callingPackage, @NonNull String namespace) { - RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess( - callingPackage, - namespace); + + if (!Flags.deprecateFlagsAndSettingsResets()) { + RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess( + callingPackage, + namespace); + } } } private static void startObservingPackages(Context context, @NonNull String updatedNamespace) { - RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context); - Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(updatedNamespace); - if (callingPackages == null) { - return; + if (!Flags.deprecateFlagsAndSettingsResets()) { + RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context); + Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet( + updatedNamespace); + if (callingPackages == null) { + return; + } + List<String> callingPackageList = new ArrayList<>(); + callingPackageList.addAll(callingPackages); + Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: " + + updatedNamespace); + PackageWatchdog.getInstance(context).startObservingHealth( + rescuePartyObserver, + callingPackageList, + DEFAULT_OBSERVING_DURATION_MS); } - List<String> callingPackageList = new ArrayList<>(); - callingPackageList.addAll(callingPackages); - Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: " - + updatedNamespace); - PackageWatchdog.getInstance(context).startObservingHealth( - rescuePartyObserver, - callingPackageList, - DEFAULT_OBSERVING_DURATION_MS); } private static void handleNativeRescuePartyResets() { - if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) { - String[] resetNativeCategories = SettingsToPropertiesMapper.getResetNativeCategories(); - for (int i = 0; i < resetNativeCategories.length; i++) { - // Don't let RescueParty reset the namespace for RescueParty switches. - if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) { - continue; + if (!Flags.deprecateFlagsAndSettingsResets()) { + if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) { + String[] resetNativeCategories = + SettingsToPropertiesMapper.getResetNativeCategories(); + for (int i = 0; i < resetNativeCategories.length; i++) { + // Don't let RescueParty reset the namespace for RescueParty switches. + if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) { + continue; + } + DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, + resetNativeCategories[i]); } - DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, - resetNativeCategories[i]); } } } @@ -401,6 +419,13 @@ public class RescueParty { } } + private static int getMaxRescueLevel() { + if (!SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) { + return Level.factoryReset(); + } + return Level.reboot(); + } + /** * Get the rescue level to perform if this is the n-th attempt at mitigating failure. * @@ -410,19 +435,30 @@ public class RescueParty { * @return the rescue level for the n-th mitigation attempt. */ private static int getRescueLevel(int mitigationCount, boolean mayPerformReboot) { - if (mitigationCount == 1) { - return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS; - } else if (mitigationCount == 2) { - return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES; - } else if (mitigationCount == 3) { - return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS; - } else if (mitigationCount == 4) { - return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_WARM_REBOOT); - } else if (mitigationCount >= 5) { - return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_FACTORY_RESET); + if (!Flags.deprecateFlagsAndSettingsResets()) { + if (mitigationCount == 1) { + return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS; + } else if (mitigationCount == 2) { + return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES; + } else if (mitigationCount == 3) { + return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS; + } else if (mitigationCount == 4) { + return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_WARM_REBOOT); + } else if (mitigationCount >= 5) { + return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_FACTORY_RESET); + } else { + Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount); + return LEVEL_NONE; + } } else { - Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount); - return LEVEL_NONE; + if (mitigationCount == 1) { + return Level.reboot(); + } else if (mitigationCount >= 2) { + return Math.min(getMaxRescueLevel(), Level.factoryReset()); + } else { + Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount); + return LEVEL_NONE; + } } } @@ -452,13 +488,13 @@ public class RescueParty { return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_WARM_REBOOT); } else if (mitigationCount == 4) { return Math.min(getMaxRescueLevel(mayPerformReboot), - RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS); + RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS); } else if (mitigationCount == 5) { return Math.min(getMaxRescueLevel(mayPerformReboot), - RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES); + RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES); } else if (mitigationCount == 6) { return Math.min(getMaxRescueLevel(mayPerformReboot), - RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS); + RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS); } else if (mitigationCount >= 7) { return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_FACTORY_RESET); } else { @@ -466,6 +502,22 @@ public class RescueParty { } } + /** + * Get the rescue level to perform if this is the n-th attempt at mitigating failure. + * + * @param mitigationCount the mitigation attempt number (1 = first attempt etc.). + * @return the rescue level for the n-th mitigation attempt. + */ + private static @RescueLevels int getRescueLevel(int mitigationCount) { + if (mitigationCount == 1) { + return Level.reboot(); + } else if (mitigationCount >= 2) { + return Math.min(getMaxRescueLevel(), Level.factoryReset()); + } else { + return Level.none(); + } + } + private static void executeRescueLevel(Context context, @Nullable String failedPackage, int level) { Slog.w(TAG, "Attempting rescue level " + levelToString(level)); @@ -493,14 +545,6 @@ public class RescueParty { private static void executeRescueLevelInternalOld(Context context, int level, @Nullable String failedPackage) throws Exception { - - // Note: DeviceConfig reset is disabled currently and would be enabled using the flag, - // after we have figured out a way to reset flags without interfering with trunk - // development. TODO: b/287618292 For enabling flag resets. - if (!Flags.allowRescuePartyFlagResets() && level <= LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS) { - return; - } - CrashRecoveryStatsLog.write(CrashRecoveryStatsLog.RESCUE_PARTY_RESET_REPORTED, level, levelToString(level)); // Try our best to reset all settings possible, and once finished @@ -508,43 +552,10 @@ public class RescueParty { Exception res = null; switch (level) { case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: - try { - resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, - level); - } catch (Exception e) { - res = e; - } - try { - resetDeviceConfig(context, /*isScoped=*/true, failedPackage); - } catch (Exception e) { - res = e; - } break; case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: - try { - resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, - level); - } catch (Exception e) { - res = e; - } - try { - resetDeviceConfig(context, /*isScoped=*/true, failedPackage); - } catch (Exception e) { - res = e; - } break; case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: - try { - resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, - level); - } catch (Exception e) { - res = e; - } - try { - resetDeviceConfig(context, /*isScoped=*/false, failedPackage); - } catch (Exception e) { - res = e; - } break; case LEVEL_WARM_REBOOT: executeWarmReboot(context, level, failedPackage); @@ -572,28 +583,29 @@ public class RescueParty { level, levelToString(level)); switch (level) { case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET: - // Enable deviceConfig reset behind flag - if (Flags.allowRescuePartyFlagResets()) { - resetDeviceConfig(context, /*isScoped=*/true, failedPackage); - } break; case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET: - // Enable deviceConfig reset behind flag - if (Flags.allowRescuePartyFlagResets()) { - resetDeviceConfig(context, /*isScoped=*/false, failedPackage); - } break; case RESCUE_LEVEL_WARM_REBOOT: executeWarmReboot(context, level, failedPackage); break; case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: - resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, level); + if (!Flags.deprecateFlagsAndSettingsResets()) { + resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, + level); + } break; case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: - resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, level); + if (!Flags.deprecateFlagsAndSettingsResets()) { + resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, + level); + } break; case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: - resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, level); + if (!Flags.deprecateFlagsAndSettingsResets()) { + resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, + level); + } break; case RESCUE_LEVEL_FACTORY_RESET: // Before the completion of Reboot, if any crash happens then PackageWatchdog @@ -610,6 +622,12 @@ public class RescueParty { private static void executeWarmReboot(Context context, int level, @Nullable String failedPackage) { + if (Flags.deprecateFlagsAndSettingsResets()) { + if (shouldThrottleReboot()) { + return; + } + } + // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog // when device shutting down. setRebootProperty(true); @@ -629,6 +647,11 @@ public class RescueParty { private static void executeFactoryReset(Context context, int level, @Nullable String failedPackage) { + if (Flags.deprecateFlagsAndSettingsResets()) { + if (shouldThrottleReboot()) { + return; + } + } setFactoryResetProperty(true); long now = System.currentTimeMillis(); setLastFactoryResetTimeMs(now); @@ -705,84 +728,31 @@ public class RescueParty { private static void resetAllSettingsIfNecessary(Context context, int mode, int level) throws Exception { - // No need to reset Settings again if they are already reset in the current level once. - if (getMaxRescueLevelAttempted() >= level) { - return; - } - setMaxRescueLevelAttempted(level); - // Try our best to reset all settings possible, and once finished - // rethrow any exception that we encountered - Exception res = null; - final ContentResolver resolver = context.getContentResolver(); - try { - Settings.Global.resetToDefaultsAsUser(resolver, null, mode, - UserHandle.SYSTEM.getIdentifier()); - } catch (Exception e) { - res = new RuntimeException("Failed to reset global settings", e); - } - for (int userId : getAllUserIds()) { + if (!Flags.deprecateFlagsAndSettingsResets()) { + // No need to reset Settings again if they are already reset in the current level once. + if (getMaxRescueLevelAttempted() >= level) { + return; + } + setMaxRescueLevelAttempted(level); + // Try our best to reset all settings possible, and once finished + // rethrow any exception that we encountered + Exception res = null; + final ContentResolver resolver = context.getContentResolver(); try { - Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId); + Settings.Global.resetToDefaultsAsUser(resolver, null, mode, + UserHandle.SYSTEM.getIdentifier()); } catch (Exception e) { - res = new RuntimeException("Failed to reset secure settings for " + userId, e); + res = new RuntimeException("Failed to reset global settings", e); } - } - if (res != null) { - throw res; - } - } - - private static void resetDeviceConfig(Context context, boolean isScoped, - @Nullable String failedPackage) throws Exception { - final ContentResolver resolver = context.getContentResolver(); - try { - if (!isScoped || failedPackage == null) { - resetAllAffectedNamespaces(context); - } else { - performScopedReset(context, failedPackage); - } - } catch (Exception e) { - throw new RuntimeException("Failed to reset config settings", e); - } - } - - private static void resetAllAffectedNamespaces(Context context) { - RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context); - Set<String> allAffectedNamespaces = rescuePartyObserver.getAllAffectedNamespaceSet(); - - Slog.w(TAG, - "Performing reset for all affected namespaces: " - + Arrays.toString(allAffectedNamespaces.toArray())); - Iterator<String> it = allAffectedNamespaces.iterator(); - while (it.hasNext()) { - String namespace = it.next(); - // Don't let RescueParty reset the namespace for RescueParty switches. - if (NAMESPACE_CONFIGURATION.equals(namespace)) { - continue; - } - DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, namespace); - } - } - - private static void performScopedReset(Context context, @NonNull String failedPackage) { - RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context); - Set<String> affectedNamespaces = rescuePartyObserver.getAffectedNamespaceSet( - failedPackage); - // If we can't find namespaces affected for current package, - // skip this round of reset. - if (affectedNamespaces != null) { - Slog.w(TAG, - "Performing scoped reset for package: " + failedPackage - + ", affected namespaces: " - + Arrays.toString(affectedNamespaces.toArray())); - Iterator<String> it = affectedNamespaces.iterator(); - while (it.hasNext()) { - String namespace = it.next(); - // Don't let RescueParty reset the namespace for RescueParty switches. - if (NAMESPACE_CONFIGURATION.equals(namespace)) { - continue; + for (int userId : getAllUserIds()) { + try { + Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId); + } catch (Exception e) { + res = new RuntimeException("Failed to reset secure settings for " + userId, e); } - DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, namespace); + } + if (res != null) { + throw res; } } } @@ -833,18 +803,28 @@ public class RescueParty { @Override public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage, @FailureReasons int failureReason, int mitigationCount) { + int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) { if (Flags.recoverabilityDetection()) { - return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, - mayPerformReboot(failedPackage), failedPackage)); + if (!Flags.deprecateFlagsAndSettingsResets()) { + impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, + mayPerformReboot(failedPackage), failedPackage)); + } else { + impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount)); + } } else { - return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, - mayPerformReboot(failedPackage))); + impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, + mayPerformReboot(failedPackage))); } - } else { - return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; } + + Slog.i(TAG, "Checking available remediations for health check failure." + + " failedPackage: " + + (failedPackage == null ? null : failedPackage.getPackageName()) + + " failureReason: " + failureReason + + " available impact: " + impact); + return impact; } @Override @@ -853,12 +833,24 @@ public class RescueParty { if (isDisabled()) { return false; } + Slog.i(TAG, "Executing remediation." + + " failedPackage: " + + (failedPackage == null ? null : failedPackage.getPackageName()) + + " failureReason: " + failureReason + + " mitigationCount: " + mitigationCount); if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) { - final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount, - mayPerformReboot(failedPackage), failedPackage) - : getRescueLevel(mitigationCount, - mayPerformReboot(failedPackage)); + final int level; + if (Flags.recoverabilityDetection()) { + if (!Flags.deprecateFlagsAndSettingsResets()) { + level = getRescueLevel(mitigationCount, mayPerformReboot(failedPackage), + failedPackage); + } else { + level = getRescueLevel(mitigationCount); + } + } else { + level = getRescueLevel(mitigationCount, mayPerformReboot(failedPackage)); + } executeRescueLevel(mContext, failedPackage == null ? null : failedPackage.getPackageName(), level); return true; @@ -892,8 +884,12 @@ public class RescueParty { return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; } if (Flags.recoverabilityDetection()) { - return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, - true, /*failedPackage=*/ null)); + if (!Flags.deprecateFlagsAndSettingsResets()) { + return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, + true, /*failedPackage=*/ null)); + } else { + return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount)); + } } else { return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true)); } @@ -905,9 +901,17 @@ public class RescueParty { return false; } boolean mayPerformReboot = !shouldThrottleReboot(); - final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount, - mayPerformReboot, /*failedPackage=*/ null) - : getRescueLevel(mitigationCount, mayPerformReboot); + final int level; + if (Flags.recoverabilityDetection()) { + if (!Flags.deprecateFlagsAndSettingsResets()) { + level = getRescueLevel(mitigationCount, mayPerformReboot, + /*failedPackage=*/ null); + } else { + level = getRescueLevel(mitigationCount); + } + } else { + level = getRescueLevel(mitigationCount, mayPerformReboot); + } executeRescueLevel(mContext, /*failedPackage=*/ null, level); return true; } @@ -933,18 +937,6 @@ public class RescueParty { return isPersistentSystemApp(failingPackage.getPackageName()); } - /** - * Returns {@code true} if Rescue Party is allowed to attempt a reboot or factory reset. - * Will return {@code false} if a factory reset was already offered recently. - */ - private boolean shouldThrottleReboot() { - Long lastResetTime = getLastFactoryResetTimeMs(); - long now = System.currentTimeMillis(); - long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG, - DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN); - return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin); - } - private boolean isPersistentSystemApp(@NonNull String packageName) { PackageManager pm = mContext.getPackageManager(); try { @@ -957,20 +949,22 @@ public class RescueParty { private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage, @NonNull String namespace) { - // Record it in calling packages to namespace map - Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage); - if (namespaceSet == null) { - namespaceSet = new ArraySet<>(); - mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet); - } - namespaceSet.add(namespace); - // Record it in namespace to calling packages map - Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace); - if (callingPackageSet == null) { - callingPackageSet = new ArraySet<>(); + if (!Flags.deprecateFlagsAndSettingsResets()) { + // Record it in calling packages to namespace map + Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage); + if (namespaceSet == null) { + namespaceSet = new ArraySet<>(); + mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet); + } + namespaceSet.add(namespace); + // Record it in namespace to calling packages map + Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace); + if (callingPackageSet == null) { + callingPackageSet = new ArraySet<>(); + } + callingPackageSet.add(callingPackage); + mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet); } - callingPackageSet.add(callingPackage); - mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet); } private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) { @@ -986,6 +980,18 @@ public class RescueParty { } } + /** + * Returns {@code true} if Rescue Party is allowed to attempt a reboot or factory reset. + * Will return {@code false} if a factory reset was already offered recently. + */ + private static boolean shouldThrottleReboot() { + Long lastResetTime = getLastFactoryResetTimeMs(); + long now = System.currentTimeMillis(); + long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG, + DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN); + return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin); + } + private static int[] getAllUserIds() { int systemUserId = UserHandle.SYSTEM.getIdentifier(); int[] userIds = { systemUserId }; @@ -1024,6 +1030,22 @@ public class RescueParty { } } + private static class Level { + static int none() { + return Flags.recoverabilityDetection() ? RESCUE_LEVEL_NONE : LEVEL_NONE; + } + + static int reboot() { + return Flags.recoverabilityDetection() ? RESCUE_LEVEL_WARM_REBOOT : LEVEL_WARM_REBOOT; + } + + static int factoryReset() { + return Flags.recoverabilityDetection() + ? RESCUE_LEVEL_FACTORY_RESET + : LEVEL_FACTORY_RESET; + } + } + private static String levelToString(int level) { if (Flags.recoverabilityDetection()) { switch (level) { diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index c18bacb51671..3e61b1da2ecc 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -1010,6 +1010,7 @@ public class Watchdog implements Dumpable { // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the // kernel log doSysRq('w'); + doSysRq('m'); doSysRq('l'); } diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java index 598f086db94d..4faadcbe0cca 100644 --- a/services/core/java/com/android/server/am/LmkdConnection.java +++ b/services/core/java/com/android/server/am/LmkdConnection.java @@ -91,10 +91,18 @@ public class LmkdConnection { @GuardedBy("mLmkdSocketLock") private LocalSocket mLmkdSocket = null; - // socket I/O streams - @GuardedBy("mLmkdSocketLock") + // mutex to synchronize socket output stream with socket creation/destruction + private final Object mLmkdOutputStreamLock = new Object(); + + // socket output stream + @GuardedBy("mLmkdOutputStreamLock") private OutputStream mLmkdOutputStream = null; - @GuardedBy("mLmkdSocketLock") + + // mutex to synchronize socket input stream with socket creation/destruction + private final Object mLmkdInputStreamLock = new Object(); + + // socket input stream + @GuardedBy("mLmkdInputStreamLock") private InputStream mLmkdInputStream = null; // buffer to store incoming data @@ -148,9 +156,13 @@ public class LmkdConnection { return false; } // connection established - mLmkdSocket = socket; - mLmkdOutputStream = ostream; - mLmkdInputStream = istream; + synchronized(mLmkdOutputStreamLock) { + synchronized(mLmkdInputStreamLock) { + mLmkdSocket = socket; + mLmkdOutputStream = ostream; + mLmkdInputStream = istream; + } + } mMsgQueue.addOnFileDescriptorEventListener(mLmkdSocket.getFileDescriptor(), EVENT_INPUT | EVENT_ERROR, new MessageQueue.OnFileDescriptorEventListener() { @@ -177,7 +189,13 @@ public class LmkdConnection { mMsgQueue.removeOnFileDescriptorEventListener( mLmkdSocket.getFileDescriptor()); IoUtils.closeQuietly(mLmkdSocket); - mLmkdSocket = null; + synchronized(mLmkdOutputStreamLock) { + synchronized(mLmkdInputStreamLock) { + mLmkdOutputStream = null; + mLmkdInputStream = null; + mLmkdSocket = null; + } + } } // wake up reply waiters if any synchronized (mReplyBufLock) { @@ -262,24 +280,33 @@ public class LmkdConnection { } private boolean write(ByteBuffer buf) { - synchronized (mLmkdSocketLock) { - try { - mLmkdOutputStream.write(buf.array(), 0, buf.position()); - } catch (IOException ex) { - return false; + boolean result = false; + + synchronized(mLmkdOutputStreamLock) { + if (mLmkdOutputStream != null) { + try { + mLmkdOutputStream.write(buf.array(), 0, buf.position()); + result = true; + } catch (IOException ex) { + } } - return true; } + + return result; } private int read(ByteBuffer buf) { - synchronized (mLmkdSocketLock) { - try { - return mLmkdInputStream.read(buf.array(), 0, buf.array().length); - } catch (IOException ex) { + int result = -1; + + synchronized(mLmkdInputStreamLock) { + if (mLmkdInputStream != null) { + try { + result = mLmkdInputStream.read(buf.array(), 0, buf.array().length); + } catch (IOException ex) { + } } - return -1; } + return result; } /** diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 64e3e8ed29c1..97678aa922a4 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -5491,8 +5491,9 @@ public final class ProcessList { void noteAppKill(final ProcessRecord app, final @Reason int reason, final @SubReason int subReason, final String msg) { if (DEBUG_PROCESSES) { - Slog.i(TAG, "note: " + app + " is being killed, reason: " + reason - + ", sub-reason: " + subReason + ", message: " + msg); + Slog.i(TAG, "note: " + app + " is being killed, reason: " + + ApplicationExitInfo.reasonCodeToString(reason) + ", sub-reason: " + + ApplicationExitInfo.subreasonToString(subReason) + ", message: " + msg); } if (app.getPid() > 0 && !app.isolated && app.getDeathRecipient() != null) { // We are killing it, put it into the dying process list. diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index f1eea728bedd..33ad49edfe87 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -787,6 +787,14 @@ public class AudioDeviceBroker { return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); } + /*package*/ boolean isBluetoothBleHeadsetActive() { + return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_HEADSET); + } + + /*package*/ boolean isBluetoothBleSpeakerActive() { + return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_SPEAKER); + } + /*package*/ boolean isDeviceConnected(@NonNull AudioDeviceAttributes device) { synchronized (mDeviceStateLock) { return mDeviceInventory.isDeviceConnected(device); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 3f49b90ad514..6787fa6a68c6 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -5665,16 +5665,25 @@ public class AudioService extends IAudioService.Stub || ringerMode == AudioManager.RINGER_MODE_SILENT; final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE && mDeviceBroker.isBluetoothScoActive(); - // Ask audio policy engine to force use Bluetooth SCO channel if needed + final boolean shouldRingBle = ringerMode == AudioManager.RINGER_MODE_VIBRATE + && (mDeviceBroker.isBluetoothBleHeadsetActive() + || mDeviceBroker.isBluetoothBleSpeakerActive()); + // Ask audio policy engine to force use Bluetooth SCO/BLE channel if needed final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid() + "/" + Binder.getCallingPid(); + int forceUse = AudioSystem.FORCE_NONE; + if (shouldRingSco) { + forceUse = AudioSystem.FORCE_BT_SCO; + } else if (shouldRingBle) { + forceUse = AudioSystem.FORCE_BT_BLE; + } sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_VIBRATE_RINGING, - shouldRingSco ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE, eventSource, 0); + forceUse, eventSource, 0); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { final boolean isMuted = isStreamMutedByRingerOrZenMode(streamType); final boolean muteAllowedBySco = - !(shouldRingSco && streamType == AudioSystem.STREAM_RING); + !((shouldRingSco || shouldRingBle) && streamType == AudioSystem.STREAM_RING); final boolean shouldZenMute = isStreamAffectedByCurrentZen(streamType); final boolean shouldMute = shouldZenMute || (ringerModeMute && isStreamAffectedByRingerMode(streamType) && muteAllowedBySco); diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 0f3f8073edcc..73ca6fbf8e5f 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -436,8 +436,13 @@ public class BtHelper { if (mBluetoothHeadset == null || mBluetoothHeadsetDevice == null) { return false; } - return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) - == BluetoothHeadset.STATE_AUDIO_CONNECTED; + try { + return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) + == BluetoothHeadset.STATE_AUDIO_CONNECTED; + } catch (Exception e) { + Log.e(TAG, "Exception while getting audio state of " + mBluetoothHeadsetDevice, e); + } + return false; } // @GuardedBy("mDeviceBroker.mSetModeLock") @@ -1051,12 +1056,16 @@ public class BtHelper { } private void checkScoAudioState() { - if (mBluetoothHeadset != null - && mBluetoothHeadsetDevice != null - && mScoAudioState == SCO_STATE_INACTIVE - && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) - != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { - mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; + try { + if (mBluetoothHeadset != null + && mBluetoothHeadsetDevice != null + && mScoAudioState == SCO_STATE_INACTIVE + && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) + != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { + mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; + } + } catch (Exception e) { + Log.e(TAG, "Exception while getting audio state of " + mBluetoothHeadsetDevice, e); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java index 6a2731d3982e..5a493e4dded8 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java @@ -120,11 +120,13 @@ public abstract class BiometricServiceRegistry<T extends BiometricServiceProvide // Register each sensor individually with BiometricService final List<P> allProps = new ArrayList<>(); for (T provider : providers) { - final List<P> props = provider.getSensorProperties(); - for (P prop : props) { - registerService(biometricService, prop); + if(provider != null) { + final List<P> props = provider.getSensorProperties(); + for (P prop : props) { + registerService(biometricService, prop); + } + allProps.addAll(props); } - allProps.addAll(props); } finishRegistration(providers, allProps); diff --git a/services/core/java/com/android/server/crashrecovery/TEST_MAPPING b/services/core/java/com/android/server/crashrecovery/TEST_MAPPING new file mode 100644 index 000000000000..4a66bac2e4ec --- /dev/null +++ b/services/core/java/com/android/server/crashrecovery/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "postsubmit": [ + { + "name": "FrameworksMockingServicesTests", + "options": [ + { + "include-filter": "com.android.server.RescuePartyTest" + } + ] + } + ] +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 88c24e0a7eff..cf4393bd4414 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -48,6 +48,7 @@ import android.view.RoundedCorners; import android.view.SurfaceControl; import com.android.internal.R; +import com.android.internal.annotations.KeepForWeakReference; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.util.function.pooled.PooledLambda; @@ -1394,8 +1395,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { } public static class Injector { - // Native callback. + // Ensure the callback is kept to preserve native weak reference lifecycle semantics. @SuppressWarnings("unused") + @KeepForWeakReference private ProxyDisplayEventReceiver mReceiver; public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) { mReceiver = new ProxyDisplayEventReceiver(looper, listener); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java index f992a2399c61..88d43b20f5f2 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java @@ -655,7 +655,11 @@ public class HdmiCecNetwork { .setPortId(physicalAddressToPortId(physicalAddress)) .setDeviceType(type) .build(); - updateCecDevice(updatedDeviceInfo); + if (deviceInfo.getPhysicalAddress() != physicalAddress) { + addCecDevice(updatedDeviceInfo); + } else { + updateCecDevice(updatedDeviceInfo); + } } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index c8c662387d16..d5f8eadcf805 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -143,6 +143,10 @@ public class HdmiControlService extends SystemService { private static final String TAG = "HdmiControlService"; private static final Locale HONG_KONG = new Locale("zh", "HK"); private static final Locale MACAU = new Locale("zh", "MO"); + private static final String TAIWAN_HantLanguageTag = "zh-Hant-TW"; + private static final String HONG_KONG_HantLanguageTag = "zh-Hant-HK"; + private static final String HONG_KONG_YUE_HantLanguageTag = "yue-Hant-HK"; + private static final String MACAU_HantLanguageTag = "zh-Hant-MO"; private static final Map<String, String> sTerminologyToBibliographicMap = createsTerminologyToBibliographicMap(); @@ -173,7 +177,11 @@ public class HdmiControlService extends SystemService { } @VisibleForTesting static String localeToMenuLanguage(Locale locale) { - if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) { + if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU) || + locale.toLanguageTag().equals(TAIWAN_HantLanguageTag) || + locale.toLanguageTag().equals(HONG_KONG_HantLanguageTag) || + locale.toLanguageTag().equals(HONG_KONG_YUE_HantLanguageTag) || + locale.toLanguageTag().equals(MACAU_HantLanguageTag)) { // Android always returns "zho" for all Chinese variants. // Use "bibliographic" code defined in CEC639-2 for traditional // Chinese used in Taiwan/Hong Kong/Macau. diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 1564b2f86218..0f7904e4ae0b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2949,6 +2949,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub hideStatusBarIconLocked(); mInFullscreenMode = false; mWindowManagerInternal.setDismissImeOnBackKeyPressed(false); + scheduleResetStylusHandwriting(); } @BinderThread diff --git a/services/core/java/com/android/server/location/altitude/AltitudeService.java b/services/core/java/com/android/server/location/altitude/AltitudeService.java index 289d4a25f208..96540c225e23 100644 --- a/services/core/java/com/android/server/location/altitude/AltitudeService.java +++ b/services/core/java/com/android/server/location/altitude/AltitudeService.java @@ -25,6 +25,7 @@ import android.frameworks.location.altitude.IAltitudeService; import android.location.Location; import android.location.altitude.AltitudeConverter; import android.os.RemoteException; +import android.util.Log; import com.android.server.SystemService; @@ -38,6 +39,8 @@ import java.io.IOException; */ public class AltitudeService extends IAltitudeService.Stub { + private static final String TAG = "AltitudeService"; + private final AltitudeConverter mAltitudeConverter = new AltitudeConverter(); private final Context mContext; @@ -59,6 +62,7 @@ public class AltitudeService extends IAltitudeService.Stub { try { mAltitudeConverter.addMslAltitudeToLocation(mContext, location); } catch (IOException e) { + Log.e(TAG, "", e); response.success = false; return response; } @@ -74,6 +78,7 @@ public class AltitudeService extends IAltitudeService.Stub { try { return mAltitudeConverter.getGeoidHeight(mContext, request); } catch (IOException e) { + Log.e(TAG, "", e); GetGeoidHeightResponse response = new GetGeoidHeightResponse(); response.success = false; return response; diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 71576465e035..7aae91b98348 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -1773,6 +1773,20 @@ public class LockSettingsService extends ILockSettings.Stub { } } + @Override + public boolean writeRepairModeCredential(int userId) { + checkWritePermission(); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mSpManager) { + long protectorId = getCurrentLskfBasedProtectorId(userId); + return mSpManager.writeRepairModeCredentialLocked(protectorId, userId); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + /** * @param savedCredential if the user is a profile with * {@link UserManager#isCredentialSharableWithParent()} with unified challenge and diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java index 17f2fcc5b9d8..bb35b378866b 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java @@ -340,6 +340,11 @@ class LockSettingsShellCommand extends ShellCommand { getOutPrintWriter().println("Profile uses unified challenge"); return false; } + if (mOld.isEmpty()) { + getOutPrintWriter().println( + "User has a lock credential, but old credential was not provided"); + return false; + } try { final boolean result = mLockPatternUtils.checkCredential(getOldCredential(), diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 773d10b1f076..478868ba6a73 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -25,6 +25,10 @@ import android.util.ArrayMap; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.tools.r8.keepanno.annotations.KeepItemKind; +import com.android.tools.r8.keepanno.annotations.KeepTarget; +import com.android.tools.r8.keepanno.annotations.UsesReflection; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; @@ -41,7 +45,13 @@ public class RankingHelper { private final Context mContext; private final RankingHandler mRankingHandler; - + @UsesReflection( + value = { + @KeepTarget( + kind = KeepItemKind.CLASS_AND_MEMBERS, + instanceOfClassConstantExclusive = NotificationSignalExtractor.class, + methodName = "<init>") + }) public RankingHelper(Context context, RankingHandler rankingHandler, RankingConfig config, ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) { mContext = context; diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 89c4f0f276af..91990048e356 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -4550,7 +4550,7 @@ final class InstallPackageHelper { PackageManagerException.INTERNAL_ERROR_SYSTEM_OVERLAY_STATIC); } } else { - if ((scanFlags & SCAN_AS_VENDOR) != 0) { + if ((scanFlags & (SCAN_AS_VENDOR | SCAN_AS_ODM)) != 0) { if (pkg.getTargetSdkVersion() < ScanPackageUtils.getVendorPartitionVersion()) { Slog.w(TAG, "System overlay " + pkg.getPackageName() + " targets an SDK below the required SDK level of vendor" diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index c8bc56ce7dcd..9b0616a6b609 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -28,6 +28,7 @@ per-file CrossProfile* = file:MULTIUSER_AND_ENTERPRISE_OWNERS per-file RestrictionsSet.java = file:MULTIUSER_AND_ENTERPRISE_OWNERS per-file UserRestriction* = file:MULTIUSER_AND_ENTERPRISE_OWNERS per-file User* = file:/MULTIUSER_OWNERS +per-file BackgroundUser* = file:/MULTIUSER_OWNERS # security per-file KeySetHandle.java = cbrubaker@google.com, nnk@google.com diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java index d1f91c89a04e..c4e3fa4213a9 100644 --- a/services/core/java/com/android/server/rollback/Rollback.java +++ b/services/core/java/com/android/server/rollback/Rollback.java @@ -16,6 +16,8 @@ package com.android.server.rollback; +import static android.crashrecovery.flags.Flags.deprecateFlagsAndSettingsResets; + import static com.android.server.rollback.RollbackManagerServiceImpl.sendFailure; import android.Manifest; @@ -622,8 +624,10 @@ class Rollback { parentSession.addChildSessionId(sessionId); } - // Clear flags. - RescueParty.resetDeviceConfigForPackages(packageNames); + if (!deprecateFlagsAndSettingsResets()) { + // Clear flags. + RescueParty.resetDeviceConfigForPackages(packageNames); + } Consumer<Intent> onResult = result -> { mHandler.post(() -> { diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index c85ceac9ea55..4f28e023da92 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -154,12 +154,22 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } } + Slog.i(TAG, "Checking available remediations for health check failure." + + " failedPackage: " + + (failedPackage == null ? null : failedPackage.getPackageName()) + + " failureReason: " + failureReason + + " available impact: " + impact); return impact; } @Override public boolean execute(@Nullable VersionedPackage failedPackage, @FailureReasons int rollbackReason, int mitigationCount) { + Slog.i(TAG, "Executing remediation." + + " failedPackage: " + + (failedPackage == null ? null : failedPackage.getPackageName()) + + " rollbackReason: " + rollbackReason + + " mitigationCount: " + mitigationCount); if (Flags.recoverabilityDetection()) { List<RollbackInfo> availableRollbacks = getAvailableRollbacks(); if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) { @@ -503,6 +513,10 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve @FailureReasons int rollbackReason) { assertInWorkerThread(); + Slog.i(TAG, "Rolling back package. RollbackId: " + rollback.getRollbackId() + + " failedPackage: " + + (failedPackage == null ? null : failedPackage.getPackageName()) + + " rollbackReason: " + rollbackReason); final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason); final String failedPackageToLog; diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index b3c31a9cfb64..a0ccc9d99d05 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -16,6 +16,7 @@ package com.android.server.trust; +import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth; import static android.service.trust.GrantTrustResult.STATUS_UNLOCKED_BY_GRANT; import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE; @@ -82,6 +83,9 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.infra.AndroidFuture; import com.android.internal.util.DumpUtils; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockSettingsInternal; +import com.android.internal.widget.LockSettingsStateListener; +import com.android.server.LocalServices; import com.android.server.SystemService; import org.xmlpull.v1.XmlPullParser; @@ -154,6 +158,7 @@ public class TrustManagerService extends SystemService { /* package */ final TrustArchive mArchive = new TrustArchive(); private final Context mContext; + private final LockSettingsInternal mLockSettings; private final LockPatternUtils mLockPatternUtils; private final KeyStoreAuthorization mKeyStoreAuthorization; private final UserManager mUserManager; @@ -245,6 +250,20 @@ public class TrustManagerService extends SystemService { private final StrongAuthTracker mStrongAuthTracker; + // Used to subscribe to device credential auth attempts. + private final LockSettingsStateListener mLockSettingsStateListener = + new LockSettingsStateListener() { + @Override + public void onAuthenticationSucceeded(int userId) { + mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, 1, userId).sendToTarget(); + } + + @Override + public void onAuthenticationFailed(int userId) { + mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, 0, userId).sendToTarget(); + } + }; + private boolean mTrustAgentsCanRun = false; private int mCurrentUser = UserHandle.USER_SYSTEM; @@ -286,6 +305,7 @@ public class TrustManagerService extends SystemService { mHandler = createHandler(injector.getLooper()); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + mLockSettings = LocalServices.getService(LockSettingsInternal.class); mLockPatternUtils = injector.getLockPatternUtils(); mKeyStoreAuthorization = injector.getKeyStoreAuthorization(); mStrongAuthTracker = new StrongAuthTracker(context, injector.getLooper()); @@ -307,6 +327,9 @@ public class TrustManagerService extends SystemService { checkNewAgents(); mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); mReceiver.register(mContext); + if (shouldTrustManagerListenForPrimaryAuth()) { + mLockSettings.registerLockSettingsStateListener(mLockSettingsStateListener); + } mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker); mFingerprintManager = mContext.getSystemService(FingerprintManager.class); mFaceManager = mContext.getSystemService(FaceManager.class); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 45ea2db3fde8..2f2512d6edca 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -131,6 +131,9 @@ import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.wallpaper.WallpaperData.BindSource; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.WindowManagerInternal; +import com.android.tools.r8.keepanno.annotations.KeepItemKind; +import com.android.tools.r8.keepanno.annotations.KeepTarget; +import com.android.tools.r8.keepanno.annotations.UsesReflection; import org.xmlpull.v1.XmlPullParserException; @@ -166,6 +169,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } @Override + @UsesReflection( + value = { + @KeepTarget( + kind = KeepItemKind.CLASS_AND_MEMBERS, + instanceOfClassConstantExclusive = IWallpaperManagerService.class, + methodName = "<init>") + }) public void onStart() { try { final Class<? extends IWallpaperManagerService> klass = diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java index c18377d76cb7..3a4d02f17efb 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java @@ -40,6 +40,10 @@ import android.content.res.Resources; import android.os.Bundle; import android.text.TextUtils; +import com.android.tools.r8.keepanno.annotations.KeepItemKind; +import com.android.tools.r8.keepanno.annotations.KeepTarget; +import com.android.tools.r8.keepanno.annotations.UsesReflection; + import java.util.ArrayList; import java.util.List; @@ -179,6 +183,13 @@ public abstract class DisplayAreaPolicy { /** * Instantiates the device-specific {@link Provider}. */ + @UsesReflection( + value = { + @KeepTarget( + kind = KeepItemKind.CLASS_AND_MEMBERS, + instanceOfClassConstantExclusive = Provider.class, + methodName = "<init>") + }) static Provider fromResources(Resources res) { String name = res.getString( com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ae5a5cb7316c..8d6be09688c4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3693,7 +3693,7 @@ public class WindowManagerService extends IWindowManager.Stub hideBootMessagesLocked(); // If the screen still doesn't come up after 30 seconds, give // up and turn it on. - mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000); + mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000 * Build.HW_TIMEOUT_MULTIPLIER); } mPolicy.systemBooted(); diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index c778398342dc..00cdeb9047b5 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1956,10 +1956,6 @@ static void handleInputChannelDisposed(JNIEnv* env, jobject /* inputChannelObj * const std::shared_ptr<InputChannel>& inputChannel, void* data) { NativeInputManager* im = static_cast<NativeInputManager*>(data); - - ALOGW("Input channel object '%s' was disposed without first being removed with " - "the input manager!", - inputChannel->getName().c_str()); im->removeInputChannel(inputChannel->getConnectionToken()); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index e19f08cb04a1..37f49e300766 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -2461,11 +2461,11 @@ public final class SystemServer implements Dumpable { t.traceEnd(); } - t.traceBegin("CertBlacklister"); + t.traceBegin("CertBlocklister"); try { - CertBlacklister blacklister = new CertBlacklister(context); + CertBlocklister blocklister = new CertBlocklister(context); } catch (Throwable e) { - reportWtf("starting CertBlacklister", e); + reportWtf("starting CertBlocklister", e); } t.traceEnd(); diff --git a/services/net/Android.bp b/services/net/Android.bp index 3d40f6445834..927146db0a24 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -21,6 +21,7 @@ java_library_static { ":services.net-sources", ], static_libs: [ + "modules-utils-build_system", "netd-client", "networkstack-client", "net-utils-services-common", diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 977a8a05d6f3..3ed6ad78343b 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -287,7 +287,7 @@ public final class ProfcollectForwardingService extends SystemService { if (randomNum < traceFrequency) { BackgroundThread.get().getThreadHandler().post(() -> { try { - mIProfcollect.trace_once("applaunch"); + mIProfcollect.trace_system("applaunch"); } catch (RemoteException e) { Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); } @@ -327,7 +327,7 @@ public final class ProfcollectForwardingService extends SystemService { // Dex2oat could take a while before it starts. Add a short delay before start tracing. BackgroundThread.get().getThreadHandler().postDelayed(() -> { try { - mIProfcollect.trace_once("dex2oat"); + mIProfcollect.trace_system("dex2oat"); } catch (RemoteException e) { Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); } @@ -398,14 +398,17 @@ public final class ProfcollectForwardingService extends SystemService { if (randomNum >= traceFrequency) { return; } - // Wait for 1s before starting tracing. + // For a small percentage a traces, we collect the initialization behavior. + boolean traceInitialization = ThreadLocalRandom.current().nextInt(10) < 1; + int traceDelay = traceInitialization ? 0 : 1000; + String traceTag = traceInitialization ? "camera_init" : "camera"; BackgroundThread.get().getThreadHandler().postDelayed(() -> { try { - mIProfcollect.trace_once("camera"); + mIProfcollect.trace_process(traceTag, "android.hardware.camera.provider"); } catch (RemoteException e) { Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); } - }, 1000); + }, traceDelay); } }, null); } diff --git a/services/proguard.flags b/services/proguard.flags index a01e7dc16147..f84eff79bb15 100644 --- a/services/proguard.flags +++ b/services/proguard.flags @@ -33,12 +33,6 @@ -keep,allowoptimization,allowaccessmodification class * extends com.android.server.SystemService { public <methods>; } --keep,allowoptimization,allowaccessmodification class * extends com.android.server.devicepolicy.BaseIDevicePolicyManager { - public <init>(...); -} --keep,allowoptimization,allowaccessmodification class com.android.server.wallpaper.WallpaperManagerService { - public <init>(...); -} # Accessed from com.android.compos APEX -keep,allowoptimization,allowaccessmodification class com.android.internal.art.ArtStatsLog { @@ -68,13 +62,6 @@ -keep public class android.hidl.manager.** { *; } -keep public class com.android.server.wm.WindowManagerInternal { *; } -# Notification extractors -# TODO(b/210510433): Revisit and consider generating from frameworks/base/core/res/res/values/config.xml. --keep,allowoptimization,allowaccessmodification public class com.android.server.notification.** implements com.android.server.notification.NotificationSignalExtractor - -# OEM provided DisplayAreaPolicy.Provider defined in frameworks/base/core/res/res/values/config.xml. --keep,allowoptimization,allowaccessmodification class com.android.server.wm.** implements com.android.server.wm.DisplayAreaPolicy$Provider - # JNI keep rules # The global keep rule for native methods allows stripping of such methods if they're unreferenced # in Java. However, because system_server explicitly registers these methods from native code, @@ -118,9 +105,6 @@ # Miscellaneous reflection keep rules # TODO(b/210510433): Revisit and fix with @Keep. --keep,allowoptimization,allowaccessmodification class com.android.server.usage.AppStandbyController { - public <init>(...); -} -keep,allowoptimization,allowaccessmodification class android.hardware.usb.gadget.** { *; } # Needed when optimizations enabled diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp index 6d3b8ac45913..7eb3441a487a 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -53,6 +53,7 @@ android_test { "mockingservicestests-utils-mockito", "mockito-target-extended-minus-junit4", "platform-compat-test-rules", + "platform-parametric-runner-lib", "platform-test-annotations", "PlatformProperties", "service-blobstore", diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java index 42814e7c775e..f2acbc31b008 100644 --- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java @@ -27,7 +27,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.RescueParty.DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN; import static com.android.server.RescueParty.LEVEL_FACTORY_RESET; -import static com.android.server.RescueParty.RESCUE_LEVEL_FACTORY_RESET; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -36,7 +35,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; import android.content.ContentResolver; import android.content.Context; @@ -47,6 +45,9 @@ import android.crashrecovery.flags.Flags; import android.os.RecoverySystem; import android.os.SystemProperties; import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.FlagsParameterization; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.DeviceConfig; import android.provider.Settings; @@ -61,6 +62,9 @@ import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Captor; @@ -74,14 +78,17 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; + /** * Test RescueParty. */ +@RunWith(Parameterized.class) public class RescuePartyTest { + @Rule + public SetFlagsRule mSetFlagsRule; private static final long CURRENT_NETWORK_TIME_MILLIS = 0L; private static final String FAKE_NATIVE_NAMESPACE1 = "native1"; private static final String FAKE_NATIVE_NAMESPACE2 = "native2"; @@ -104,9 +111,6 @@ public class RescuePartyTest { private static final String PROP_DISABLE_FACTORY_RESET_FLAG = "persist.device_config.configuration.disable_rescue_party_factory_reset"; - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - private MockitoSession mSession; private HashMap<String, String> mSystemSettingsMap; private HashMap<String, String> mCrashRecoveryPropertiesMap; @@ -130,6 +134,17 @@ public class RescuePartyTest { @Captor private ArgumentCaptor<List<String>> mPackageListCaptor; + @Parameters(name = "{0}") + public static List<FlagsParameterization> getFlags() { + return FlagsParameterization.allCombinationsOf( + Flags.FLAG_RECOVERABILITY_DETECTION, + Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS); + } + + public RescuePartyTest(FlagsParameterization flags) { + mSetFlagsRule = new SetFlagsRule(flags); + } + @Before public void setUp() throws Exception { mSession = @@ -227,9 +242,6 @@ public class RescuePartyTest { setCrashRecoveryPropRescueBootCount(0); SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true)); SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false)); - - // enable flag resets for tests - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_RESCUE_PARTY_FLAG_RESETS); } @After @@ -238,10 +250,10 @@ public class RescuePartyTest { } @Test - public void testBootLoopDetectionWithExecutionForAllRescueLevels() { + @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION, + Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS}) + public void testBootLoop() { // this is old test where the flag needs to be disabled - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), any(Executor.class), @@ -250,9 +262,6 @@ public class RescuePartyTest { noteBoot(1); - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null, - verifiedTimesMap); - // Record DeviceConfig accesses RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue(); @@ -262,15 +271,8 @@ public class RescuePartyTest { final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2}; noteBoot(2); - - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedAllResetNamespaces, - verifiedTimesMap); - noteBoot(3); - verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces, - verifiedTimesMap); - noteBoot(4); assertTrue(RescueParty.isRebootPropertySet()); @@ -278,10 +280,22 @@ public class RescuePartyTest { noteBoot(5); assertTrue(RescueParty.isFactoryResetPropertySet()); } + @Test + @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testBootLoopNoFlags() { + // this is old test where the flag needs to be disabled + noteBoot(1); + assertTrue(RescueParty.isRebootPropertySet()); + + setCrashRecoveryPropAttemptingReboot(false); + noteBoot(2); + assertTrue(RescueParty.isFactoryResetPropertySet()); + } @Test - public void testBootLoopDetectionWithExecutionForAllRescueLevelsRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); + @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION) + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testBootLoopRecoverability() { RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), any(Executor.class), @@ -295,13 +309,14 @@ public class RescuePartyTest { final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2}; + noteBoot(1); - verifyDeviceConfigReset(expectedAllResetNamespaces, verifiedTimesMap); noteBoot(2); assertTrue(RescueParty.isRebootPropertySet()); noteBoot(3); + verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_DEFAULTS); noteBoot(4); @@ -316,25 +331,14 @@ public class RescuePartyTest { } @Test - public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() { + @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION, + Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS}) + public void testPersistentAppCrash() { // this is old test where the flag needs to be disabled - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - noteAppCrash(1, true); - - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null, - /*configResetVerifiedTimesMap=*/ null); - noteAppCrash(2, true); - - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null, - /*configResetVerifiedTimesMap=*/ null); - noteAppCrash(3, true); - verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null, - /*configResetVerifiedTimesMap=*/ null); - noteAppCrash(4, true); assertTrue(RescueParty.isRebootPropertySet()); @@ -344,8 +348,21 @@ public class RescuePartyTest { } @Test - public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevelsRecoverability() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); + @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testPersistentAppCrashNoFlags() { + // this is old test where the flag needs to be disabled + noteAppCrash(1, true); + assertTrue(RescueParty.isRebootPropertySet()); + + setCrashRecoveryPropAttemptingReboot(false); + noteAppCrash(2, true); + assertTrue(RescueParty.isFactoryResetPropertySet()); + } + + @Test + @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION) + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testPersistentAppCrashRecoverability() { RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), any(Executor.class), @@ -362,10 +379,8 @@ public class RescuePartyTest { final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2}; noteAppCrash(1, true); - verifyDeviceConfigReset(expectedResetNamespaces, verifiedTimesMap); noteAppCrash(2, true); - verifyDeviceConfigReset(expectedAllResetNamespaces, verifiedTimesMap); noteAppCrash(3, true); assertTrue(RescueParty.isRebootPropertySet()); @@ -385,26 +400,13 @@ public class RescuePartyTest { } @Test - public void testNonPersistentAppOnlyPerformsFlagResets() { + @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION, + Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS}) + public void testNonPersistentApp() { // this is old test where the flag needs to be disabled - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - noteAppCrash(1, false); - - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null, - /*configResetVerifiedTimesMap=*/ null); - noteAppCrash(2, false); - - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null, - /*configResetVerifiedTimesMap=*/ null); - noteAppCrash(3, false); - - verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null, - /*configResetVerifiedTimesMap=*/ null); - - noteAppCrash(4, false); assertFalse(RescueParty.isRebootPropertySet()); noteAppCrash(5, false); @@ -412,8 +414,9 @@ public class RescuePartyTest { } @Test + @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION) + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testNonPersistentAppOnlyPerformsFlagResetsRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), any(Executor.class), @@ -430,10 +433,8 @@ public class RescuePartyTest { final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2}; noteAppCrash(1, false); - verifyDeviceConfigReset(expectedResetNamespaces, verifiedTimesMap); noteAppCrash(2, false); - verifyDeviceConfigReset(expectedAllResetNamespaces, verifiedTimesMap); noteAppCrash(3, false); assertFalse(RescueParty.isRebootPropertySet()); @@ -451,135 +452,6 @@ public class RescuePartyTest { } @Test - public void testNonPersistentAppCrashDetectionWithScopedResets() { - // this is old test where the flag needs to be disabled - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - - RescueParty.onSettingsProviderPublished(mMockContext); - verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), - any(Executor.class), - mMonitorCallbackCaptor.capture())); - - // Record DeviceConfig accesses - RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); - DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue(); - monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1); - monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2); - monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE2); - monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3); - - // Fake DeviceConfig value changes - monitorCallback.onNamespaceUpdate(NAMESPACE1); - verify(mMockPackageWatchdog).startObservingHealth(observer, - Arrays.asList(CALLING_PACKAGE1), RescueParty.DEFAULT_OBSERVING_DURATION_MS); - monitorCallback.onNamespaceUpdate(NAMESPACE2); - verify(mMockPackageWatchdog, times(2)).startObservingHealth(eq(observer), - mPackageListCaptor.capture(), - eq(RescueParty.DEFAULT_OBSERVING_DURATION_MS)); - monitorCallback.onNamespaceUpdate(NAMESPACE3); - verify(mMockPackageWatchdog).startObservingHealth(observer, - Arrays.asList(CALLING_PACKAGE2), RescueParty.DEFAULT_OBSERVING_DURATION_MS); - assertTrue(mPackageListCaptor.getValue().containsAll( - Arrays.asList(CALLING_PACKAGE1, CALLING_PACKAGE2))); - // Perform and verify scoped resets - final String[] expectedResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2}; - final String[] expectedAllResetNamespaces = - new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3}; - HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>(); - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, expectedResetNamespaces, - verifiedTimesMap); - - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2); - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedResetNamespaces, - verifiedTimesMap); - - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3); - verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces, - verifiedTimesMap); - - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4); - assertFalse(RescueParty.isRebootPropertySet()); - - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5); - assertFalse(RescueParty.isFactoryResetPropertySet()); - } - - @Test - public void testNonDeviceConfigSettingsOnlyResetOncePerLevel() { - // this is old test where the flag needs to be disabled - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - - RescueParty.onSettingsProviderPublished(mMockContext); - verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), - any(Executor.class), - mMonitorCallbackCaptor.capture())); - - // Record DeviceConfig accesses - RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); - DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue(); - monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1); - monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2); - monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE2); - monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3); - // Fake DeviceConfig value changes - monitorCallback.onNamespaceUpdate(NAMESPACE1); - monitorCallback.onNamespaceUpdate(NAMESPACE2); - monitorCallback.onNamespaceUpdate(NAMESPACE3); - // Perform and verify scoped resets - final String[] expectedPackage1ResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2}; - final String[] expectedPackage2ResetNamespaces = new String[]{NAMESPACE2, NAMESPACE3}; - final String[] expectedAllResetNamespaces = - new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3}; - HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>(); - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, - expectedPackage1ResetNamespaces, verifiedTimesMap); - - // Settings.Global & Settings.Secure should still remain the same execution times. - observer.execute(new VersionedPackage( - CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, - expectedPackage2ResetNamespaces, verifiedTimesMap); - - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2); - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, - expectedPackage1ResetNamespaces, verifiedTimesMap); - - // Settings.Global & Settings.Secure should still remain the same execution times. - observer.execute(new VersionedPackage( - CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2); - verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, - expectedPackage2ResetNamespaces, verifiedTimesMap); - - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3); - verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces, - verifiedTimesMap); - - // Settings.Global & Settings.Secure should still remain the same execution times. - observer.execute(new VersionedPackage( - CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3); - verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces, - verifiedTimesMap); - - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4); - assertFalse(RescueParty.isRebootPropertySet()); - - observer.execute(new VersionedPackage( - CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5); - assertFalse(RescueParty.isFactoryResetPropertySet()); - } - - @Test public void testIsRecoveryTriggeredReboot() { for (int i = 0; i < LEVEL_FACTORY_RESET; i++) { noteBoot(i + 1); @@ -592,19 +464,6 @@ public class RescuePartyTest { } @Test - public void testIsRecoveryTriggeredRebootRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) { - noteBoot(i + 1); - } - assertFalse(RescueParty.isFactoryResetPropertySet()); - setCrashRecoveryPropAttemptingReboot(false); - noteBoot(RESCUE_LEVEL_FACTORY_RESET + 1); - assertTrue(RescueParty.isRecoveryTriggeredReboot()); - assertTrue(RescueParty.isFactoryResetPropertySet()); - } - - @Test public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompleted() { for (int i = 0; i < LEVEL_FACTORY_RESET; i++) { noteBoot(i + 1); @@ -623,25 +482,6 @@ public class RescuePartyTest { } @Test - public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompletedRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) { - noteBoot(i + 1); - } - int mitigationCount = RESCUE_LEVEL_FACTORY_RESET + 1; - assertFalse(RescueParty.isFactoryResetPropertySet()); - noteBoot(mitigationCount++); - assertFalse(RescueParty.isFactoryResetPropertySet()); - noteBoot(mitigationCount++); - assertFalse(RescueParty.isFactoryResetPropertySet()); - noteBoot(mitigationCount++); - setCrashRecoveryPropAttemptingReboot(false); - noteBoot(mitigationCount + 1); - assertTrue(RescueParty.isRecoveryTriggeredReboot()); - assertTrue(RescueParty.isFactoryResetPropertySet()); - } - - @Test public void testThrottlingOnBootFailures() { setCrashRecoveryPropAttemptingReboot(false); long now = System.currentTimeMillis(); @@ -655,20 +495,6 @@ public class RescuePartyTest { } @Test - public void testThrottlingOnBootFailuresRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - setCrashRecoveryPropAttemptingReboot(false); - long now = System.currentTimeMillis(); - long beforeTimeout = now - TimeUnit.MINUTES.toMillis( - DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN - 1); - setCrashRecoveryPropLastFactoryReset(beforeTimeout); - for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) { - noteBoot(i); - } - assertFalse(RescueParty.isRecoveryTriggeredReboot()); - } - - @Test public void testThrottlingOnAppCrash() { setCrashRecoveryPropAttemptingReboot(false); long now = System.currentTimeMillis(); @@ -682,20 +508,6 @@ public class RescuePartyTest { } @Test - public void testThrottlingOnAppCrashRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - setCrashRecoveryPropAttemptingReboot(false); - long now = System.currentTimeMillis(); - long beforeTimeout = now - TimeUnit.MINUTES.toMillis( - DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN - 1); - setCrashRecoveryPropLastFactoryReset(beforeTimeout); - for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) { - noteAppCrash(i + 1, true); - } - assertFalse(RescueParty.isRecoveryTriggeredReboot()); - } - - @Test public void testNotThrottlingAfterTimeoutOnBootFailures() { setCrashRecoveryPropAttemptingReboot(false); long now = System.currentTimeMillis(); @@ -709,20 +521,6 @@ public class RescuePartyTest { } @Test - public void testNotThrottlingAfterTimeoutOnBootFailuresRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - setCrashRecoveryPropAttemptingReboot(false); - long now = System.currentTimeMillis(); - long afterTimeout = now - TimeUnit.MINUTES.toMillis( - DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN + 1); - setCrashRecoveryPropLastFactoryReset(afterTimeout); - for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) { - noteBoot(i); - } - assertTrue(RescueParty.isRecoveryTriggeredReboot()); - } - - @Test public void testNotThrottlingAfterTimeoutOnAppCrash() { setCrashRecoveryPropAttemptingReboot(false); long now = System.currentTimeMillis(); @@ -736,20 +534,7 @@ public class RescuePartyTest { } @Test - public void testNotThrottlingAfterTimeoutOnAppCrashRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - setCrashRecoveryPropAttemptingReboot(false); - long now = System.currentTimeMillis(); - long afterTimeout = now - TimeUnit.MINUTES.toMillis( - DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN + 1); - setCrashRecoveryPropLastFactoryReset(afterTimeout); - for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) { - noteAppCrash(i + 1, true); - } - assertTrue(RescueParty.isRecoveryTriggeredReboot()); - } - - @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testNativeRescuePartyResets() { doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed()); doReturn(FAKE_RESET_NATIVE_NAMESPACES).when( @@ -765,7 +550,6 @@ public class RescuePartyTest { @Test public void testExplicitlyEnablingAndDisablingRescue() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false)); SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true)); assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage, @@ -778,7 +562,6 @@ public class RescuePartyTest { @Test public void testDisablingRescueByDeviceConfigFlag() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false)); SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(true)); @@ -804,24 +587,10 @@ public class RescuePartyTest { } @Test - public void testDisablingFactoryResetByDeviceConfigFlagRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, Boolean.toString(true)); - - for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) { - noteBoot(i + 1); - } - assertFalse(RescueParty.isFactoryResetPropertySet()); - - // Restore the property value initialized in SetUp() - SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, ""); - } - - @Test + @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION, + Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS}) public void testHealthCheckLevels() { // this is old test where the flag needs to be disabled - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); // Ensure that no action is taken for cases where the failure reason is unknown @@ -847,8 +616,9 @@ public class RescuePartyTest { } @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION) public void testHealthCheckLevelsRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); // Ensure that no action is taken for cases where the failure reason is unknown @@ -863,33 +633,53 @@ public class RescuePartyTest { assertEquals(observer.onHealthCheckFailed(sFailingPackage, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2), - PackageHealthObserverImpact.USER_IMPACT_LEVEL_20); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_40); assertEquals(observer.onHealthCheckFailed(sFailingPackage, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3), - PackageHealthObserverImpact.USER_IMPACT_LEVEL_20); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_40); assertEquals(observer.onHealthCheckFailed(sFailingPackage, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4), - PackageHealthObserverImpact.USER_IMPACT_LEVEL_20); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_40); assertEquals(observer.onHealthCheckFailed(sFailingPackage, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5), - PackageHealthObserverImpact.USER_IMPACT_LEVEL_20); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_40); assertEquals(observer.onHealthCheckFailed(sFailingPackage, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 6), - PackageHealthObserverImpact.USER_IMPACT_LEVEL_20); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_40); assertEquals(observer.onHealthCheckFailed(sFailingPackage, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 7), - PackageHealthObserverImpact.USER_IMPACT_LEVEL_20); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_40); } + @Test + @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testHealthCheckLevelsNoFlags() { + // this is old test where the flag needs to be disabled + RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); + // Ensure that no action is taken for cases where the failure reason is unknown + assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN, 1), + PackageHealthObserverImpact.USER_IMPACT_LEVEL_0); + + // Ensure the correct user impact is returned for each mitigation count. + assertEquals(observer.onHealthCheckFailed(null, + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1), + PackageHealthObserverImpact.USER_IMPACT_LEVEL_50); + + assertEquals(observer.onHealthCheckFailed(null, + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2), + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); + } @Test + @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION, + Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS}) public void testBootLoopLevels() { // this is old test where the flag needs to be disabled - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); + RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); @@ -902,11 +692,12 @@ public class RescuePartyTest { } @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION) public void testBootLoopLevelsRecoverabilityDetection() { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); - assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_20); + assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_40); assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50); assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_LEVEL_71); assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_LEVEL_75); @@ -915,6 +706,16 @@ public class RescuePartyTest { } @Test + @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testBootLoopLevelsNoFlags() { + RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); + + assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50); + assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); + } + + @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testResetDeviceConfigForPackagesOnlyRuntimeMap() { RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), @@ -945,6 +746,7 @@ public class RescuePartyTest { } @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testResetDeviceConfigForPackagesOnlyPresetMap() { RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), @@ -953,7 +755,7 @@ public class RescuePartyTest { String presetMapping = NAMESPACE1 + ":" + CALLING_PACKAGE1 + "," + NAMESPACE2 + ":" + CALLING_PACKAGE2 + "," - + NAMESPACE3 + ":" + CALLING_PACKAGE1; + + NAMESPACE3 + ":" + CALLING_PACKAGE1; doReturn(presetMapping).when(() -> DeviceConfig.getString( eq(RescueParty.NAMESPACE_CONFIGURATION), eq(RescueParty.NAMESPACE_TO_PACKAGE_MAPPING_FLAG), @@ -966,6 +768,7 @@ public class RescuePartyTest { } @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testResetDeviceConfigForPackagesBothMaps() { RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), @@ -1002,6 +805,7 @@ public class RescuePartyTest { } @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testResetDeviceConfigNoExceptionWhenFlagMalformed() { RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), @@ -1037,7 +841,6 @@ public class RescuePartyTest { private void verifySettingsResets(int resetMode, String[] resetNamespaces, HashMap<String, Integer> configResetVerifiedTimesMap) { verifyOnlySettingsReset(resetMode); - verifyDeviceConfigReset(resetNamespaces, configResetVerifiedTimesMap); } private void verifyOnlySettingsReset(int resetMode) { @@ -1054,26 +857,6 @@ public class RescuePartyTest { eq(resetMode), anyInt()), never()); } - private void verifyDeviceConfigReset(String[] resetNamespaces, - Map<String, Integer> configResetVerifiedTimesMap) { - if (resetNamespaces == null) { - verify(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()), never()); - } else { - for (String namespace : resetNamespaces) { - int verifiedTimes = 0; - if (configResetVerifiedTimesMap != null - && configResetVerifiedTimesMap.get(namespace) != null) { - verifiedTimes = configResetVerifiedTimesMap.get(namespace); - } - verify(() -> DeviceConfig.resetToDefaults(RescueParty.DEVICE_CONFIG_RESET_MODE, - namespace), times(verifiedTimes + 1)); - if (configResetVerifiedTimesMap != null) { - configResetVerifiedTimesMap.put(namespace, verifiedTimes + 1); - } - } - } - } - private void noteBoot(int mitigationCount) { RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation(mitigationCount); } diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java index 7aec42b7eceb..1a398c5f1ec3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java @@ -16,6 +16,8 @@ package com.android.server.trust; +import static android.security.Flags.FLAG_SHOULD_TRUST_MANAGER_LISTEN_FOR_PRIMARY_AUTH; +import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth; import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; @@ -43,6 +45,7 @@ import static java.util.Collections.singleton; import android.Manifest; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; @@ -72,6 +75,8 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.flag.junit.FlagsParameterization; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.security.KeyStoreAuthorization; import android.service.trust.GrantTrustResult; @@ -90,6 +95,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils.StrongAuthTracker; import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.StrongAuthFlags; import com.android.internal.widget.LockSettingsInternal; +import com.android.internal.widget.LockSettingsStateListener; import com.android.modules.utils.testing.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -100,6 +106,7 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; @@ -111,7 +118,16 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + +@RunWith(ParameterizedAndroidJunit4.class) public class TrustManagerServiceTest { + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return FlagsParameterization.allCombinationsOf( + FLAG_SHOULD_TRUST_MANAGER_LISTEN_FOR_PRIMARY_AUTH); + } @Rule public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) @@ -121,6 +137,9 @@ public class TrustManagerServiceTest { .build(); @Rule + public final SetFlagsRule mSetFlagsRule; + + @Rule public final MockContext mMockContext = new MockContext( ApplicationProvider.getApplicationContext()); @@ -142,6 +161,7 @@ public class TrustManagerServiceTest { private final Map<ComponentName, ITrustAgentService.Stub> mMockTrustAgents = new HashMap<>(); private @Mock ActivityManager mActivityManager; + private @Mock ActivityManagerInternal mActivityManagerInternal; private @Mock AlarmManager mAlarmManager; private @Mock BiometricManager mBiometricManager; private @Mock DevicePolicyManager mDevicePolicyManager; @@ -158,6 +178,11 @@ public class TrustManagerServiceTest { private HandlerThread mHandlerThread; private TrustManagerService mService; private ITrustManager mTrustManager; + private ActivityManagerInternal mPreviousActivityManagerInternal; + + public TrustManagerServiceTest(FlagsParameterization flags) { + mSetFlagsRule = new SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT, flags); + } @Before public void setUp() throws Exception { @@ -210,6 +235,11 @@ public class TrustManagerServiceTest { mMockContext.setMockPackageManager(mPackageManager); mMockContext.addMockSystemService(UserManager.class, mUserManager); doReturn(mWindowManager).when(() -> WindowManagerGlobal.getWindowManagerService()); + mPreviousActivityManagerInternal = LocalServices.getService( + ActivityManagerInternal.class); + LocalServices.removeServiceForTest(ActivityManagerInternal.class); + LocalServices.addService(ActivityManagerInternal.class, + mActivityManagerInternal); LocalServices.addService(SystemServiceManager.class, mock(SystemServiceManager.class)); grantPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE); @@ -257,7 +287,14 @@ public class TrustManagerServiceTest { @After public void tearDown() { LocalServices.removeServiceForTest(SystemServiceManager.class); - mHandlerThread.quit(); + LocalServices.removeServiceForTest(ActivityManagerInternal.class); + if (mPreviousActivityManagerInternal != null) { + LocalServices.addService(ActivityManagerInternal.class, + mPreviousActivityManagerInternal); + } + if (mHandlerThread != null) { + mHandlerThread.quit(); + } } @Test @@ -579,11 +616,27 @@ public class TrustManagerServiceTest { } private void attemptSuccessfulUnlock(int userId) throws RemoteException { - mTrustManager.reportUnlockAttempt(/* successful= */ true, userId); + if (shouldTrustManagerListenForPrimaryAuth()) { + ArgumentCaptor<LockSettingsStateListener> captor = + ArgumentCaptor.forClass(LockSettingsStateListener.class); + verify(mLockSettingsInternal).registerLockSettingsStateListener(captor.capture()); + LockSettingsStateListener listener = captor.getValue(); + listener.onAuthenticationSucceeded(userId); + } else { + mTrustManager.reportUnlockAttempt(/* successful= */ true, userId); + } } private void attemptFailedUnlock(int userId) throws RemoteException { - mTrustManager.reportUnlockAttempt(/* successful= */ false, userId); + if (shouldTrustManagerListenForPrimaryAuth()) { + ArgumentCaptor<LockSettingsStateListener> captor = + ArgumentCaptor.forClass(LockSettingsStateListener.class); + verify(mLockSettingsInternal).registerLockSettingsStateListener(captor.capture()); + LockSettingsStateListener listener = captor.getValue(); + listener.onAuthenticationFailed(userId); + } else { + mTrustManager.reportUnlockAttempt(/* successful= */ false, userId); + } } private void grantRenewableTrust(ITrustAgentServiceCallback callback) throws RemoteException { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java index 1ad9ce02daa3..b8b191543e90 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java @@ -396,7 +396,7 @@ public class HdmiCecNetworkTest { } @Test - public void cecDevices_tracking_updatesPhysicalAddress() { + public void cecDevices_tracking_updatesPhysicalAddress_add() { int logicalAddress = Constants.ADDR_PLAYBACK_1; int initialPhysicalAddress = 0x1000; int updatedPhysicalAddress = 0x2000; @@ -415,11 +415,12 @@ public class HdmiCecNetworkTest { assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(updatedPhysicalAddress); assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(type); - // ADD for physical address first detected - // UPDATE for updating device with new physical address + // Handle case where PA is changed: Update CEC device information by calling + // addCecDevice(). assertThat(mDeviceEventListenerStatuses).containsExactly( HdmiControlManager.DEVICE_EVENT_ADD_DEVICE, - HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE); + HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE, + HdmiControlManager.DEVICE_EVENT_ADD_DEVICE); } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java index 70150c507460..4396c679ec24 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java @@ -19,6 +19,8 @@ package com.android.server.locksettings; import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE; import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; @@ -199,6 +201,27 @@ public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests { .getResponseCode()); } + @Test + public void writeRepairModeCredential_noLock() { + assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isFalse(); + } + + @Test + public void writeRepairModeCredential_hasLock() { + mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); + assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isTrue(); + } + + @Test + public void writeRepairModeCredential_verifyRepairModeUser() { + mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); + mService.writeRepairModeCredential(PRIMARY_USER_ID); + setRepairModeActive(true); + + var response = mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0); + assertThat(response.isMatched()).isTrue(); + } + private void setRepairModeActive(boolean active) { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.REPAIR_MODE_ACTIVE, active ? 1 : 0); diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java index 49e9232ad535..14c9ea51c618 100644 --- a/telecomm/java/android/telecom/CallAudioState.java +++ b/telecomm/java/android/telecom/CallAudioState.java @@ -159,7 +159,7 @@ public final class CallAudioState implements Parcelable { @Override public String toString() { String bluetoothDeviceList = supportedBluetoothDevices.stream() - .map(BluetoothDevice::getAddress).collect(Collectors.joining(", ")); + .map(BluetoothDevice::toString).collect(Collectors.joining(", ")); return String.format(Locale.US, "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s, " + diff --git a/telephony/OWNERS b/telephony/OWNERS index 7607c64150d8..92af034217a9 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -15,4 +15,4 @@ per-file CarrierConfigManager.java=set noparent per-file CarrierConfigManager.java=amruthr@google.com,tgunn@google.com,rgreenwalt@google.com,satk@google.com #Domain Selection is jointly owned, add additional owners for domain selection specific files -per-file TransportSelectorCallback.java,WwanSelectorCallback.java,DomainSelectionService.java,DomainSelectionService.aidl,DomainSelector.java,EmergencyRegResult.java,EmergencyRegResult.aidl,IDomainSelectionServiceController.aidl,IDomainSelector.aidl,ITransportSelectorCallback.aidl,ITransportSelectorResultCallback.aidl,IWwanSelectorCallback.aidl,IWwanSelectorResultCallback.aidl=hwangoo@google.com,forestchoi@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,radhikaagrawal@google.com,jdyou@google.com +per-file TransportSelectorCallback.java,WwanSelectorCallback.java,DomainSelectionService.java,DomainSelectionService.aidl,DomainSelector.java,EmergencyRegResult.java,EmergencyRegResult.aidl,IDomainSelectionServiceController.aidl,IDomainSelector.aidl,ITransportSelectorCallback.aidl,ITransportSelectorResultCallback.aidl,IWwanSelectorCallback.aidl,IWwanSelectorResultCallback.aidl=hwangoo@google.com,jaesikkong@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,radhikaagrawal@google.com,jdyou@google.com diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java index cf38bea55f2c..6bf7ff501217 100644 --- a/test-mock/src/android/test/mock/MockContext.java +++ b/test-mock/src/android/test/mock/MockContext.java @@ -479,6 +479,15 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions, int appOp, Bundle options, + BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, + String initialData, Bundle initialExtras) { + throw new UnsupportedOperationException(); + } + @Override public void sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/AndroidManifest.xml b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/AndroidManifest.xml index 3363af477dcb..27a8b2a0611b 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/AndroidManifest.xml +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/AndroidManifest.xml @@ -18,7 +18,7 @@ android:versionCode="1" android:versionName="1.0" > - <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17" /> + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="17" /> <instrumentation android:name="android.test.InstrumentationTestRunner" diff --git a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java index 5460e4e87e2f..64dbe719311a 100644 --- a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java +++ b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java @@ -43,6 +43,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -392,6 +393,7 @@ public class AttachedChoreographerTest { } @Test + @Ignore("Can be enabled only after b/330536267 is ready") public void testChoreographerDivisorRefreshRate() { for (int divisor : new int[]{2, 3}) { CountDownLatch continueLatch = new CountDownLatch(1); @@ -420,6 +422,7 @@ public class AttachedChoreographerTest { } @Test + @Ignore("Can be enabled only after b/330536267 is ready") public void testChoreographerAttachedAfterSetFrameRate() { Log.i(TAG, "starting testChoreographerAttachedAfterSetFrameRate"); diff --git a/tests/HugeBackup/AndroidManifest.xml b/tests/HugeBackup/AndroidManifest.xml index 945e59bd36ed..92445dddef5a 100644 --- a/tests/HugeBackup/AndroidManifest.xml +++ b/tests/HugeBackup/AndroidManifest.xml @@ -25,7 +25,7 @@ android:versionName="1.0"> <!-- The backup/restore mechanism was introduced in API version 8 --> - <uses-sdk android:minSdkVersion="8" + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="8"/> <application android:label="Huge Backup" diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java index 489ef4444e1d..3722fefb12ad 100644 --- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java +++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java @@ -47,6 +47,8 @@ import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener; import android.os.Handler; import android.os.SystemProperties; import android.os.test.TestLooper; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.DeviceConfig; import android.util.AtomicFile; @@ -288,7 +290,8 @@ public class CrashRecoveryTest { } @Test - public void testBootLoopWithRescuePartyAndRollbackPackageHealthObserver() throws Exception { + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testBootLoopWithRescuePartyAndRollbackObserver() throws Exception { PackageWatchdog watchdog = createWatchdog(); RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); RollbackPackageHealthObserver rollbackObserver = @@ -360,6 +363,56 @@ public class CrashRecoveryTest { verify(rescuePartyObserver, never()).executeBootLoopMitigation(2); } + @Test + @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testBootLoopWithRescuePartyAndRollbackObserverNoFlags() throws Exception { + PackageWatchdog watchdog = createWatchdog(); + RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); + RollbackPackageHealthObserver rollbackObserver = + setUpRollbackPackageHealthObserver(watchdog); + + verify(rescuePartyObserver, never()).executeBootLoopMitigation(1); + verify(rollbackObserver, never()).executeBootLoopMitigation(1); + for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { + watchdog.noteBoot(); + } + verify(rescuePartyObserver).executeBootLoopMitigation(1); + verify(rescuePartyObserver, never()).executeBootLoopMitigation(2); + verify(rollbackObserver, never()).executeBootLoopMitigation(1); + + watchdog.noteBoot(); + + verify(rescuePartyObserver, never()).executeBootLoopMitigation(2); + verify(rollbackObserver).executeBootLoopMitigation(1); + verify(rollbackObserver, never()).executeBootLoopMitigation(2); + // Update the list of available rollbacks after executing bootloop mitigation once + when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_HIGH, + ROLLBACK_INFO_MANUAL)); + + watchdog.noteBoot(); + + verify(rescuePartyObserver, never()).executeBootLoopMitigation(2); + verify(rollbackObserver).executeBootLoopMitigation(2); + verify(rollbackObserver, never()).executeBootLoopMitigation(3); + // Update the list of available rollbacks after executing bootloop mitigation + when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL)); + + watchdog.noteBoot(); + + verify(rescuePartyObserver).executeBootLoopMitigation(2); + verify(rescuePartyObserver, never()).executeBootLoopMitigation(3); + verify(rollbackObserver, never()).executeBootLoopMitigation(3); + + moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1); + Mockito.reset(rescuePartyObserver); + + for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { + watchdog.noteBoot(); + } + verify(rescuePartyObserver).executeBootLoopMitigation(1); + verify(rescuePartyObserver, never()).executeBootLoopMitigation(2); + } + RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) { RollbackPackageHealthObserver rollbackObserver = spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager)); diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml index 30cf345db34d..2f6c0dd14adc 100644 --- a/tests/TrustTests/AndroidManifest.xml +++ b/tests/TrustTests/AndroidManifest.xml @@ -78,6 +78,7 @@ <action android:name="android.service.trust.TrustAgentService" /> </intent-filter> </service> + <service android:name=".IsActiveUnlockRunningTrustAgent" android:exported="true" @@ -88,6 +89,16 @@ </intent-filter> </service> + <service + android:name=".UnlockAttemptTrustAgent" + android:exported="true" + android:label="Test Agent" + android:permission="android.permission.BIND_TRUST_AGENT"> + <intent-filter> + <action android:name="android.service.trust.TrustAgentService" /> + </intent-filter> + </service> + </application> <!-- self-instrumenting test package. --> diff --git a/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt b/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt new file mode 100644 index 000000000000..f9e004bcd29e --- /dev/null +++ b/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.trust.test + +import android.app.trust.TrustManager +import android.content.Context +import android.security.Flags.shouldTrustManagerListenForPrimaryAuth +import android.trust.BaseTrustAgentService +import android.trust.TrustTestActivity +import android.trust.test.lib.LockStateTrackingRule +import android.trust.test.lib.ScreenLockRule +import android.trust.test.lib.TestTrustListener +import android.trust.test.lib.TrustAgentRule +import android.util.Log +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.RuleChain +import org.junit.runner.RunWith + +/** + * Test for the impacts of reporting unlock attempts. + * + * atest TrustTests:UnlockAttemptTest + */ +@RunWith(AndroidJUnit4::class) +class UnlockAttemptTest { + private val context = getApplicationContext<Context>() + private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager + private val userId = context.userId + private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java) + private val screenLockRule = ScreenLockRule(requireStrongAuth = true) + private val lockStateTrackingRule = LockStateTrackingRule() + private val trustAgentRule = + TrustAgentRule<UnlockAttemptTrustAgent>(startUnlocked = false, startEnabled = false) + + private val trustListener = UnlockAttemptTrustListener() + private val agent get() = trustAgentRule.agent + + @get:Rule + val rule: RuleChain = + RuleChain.outerRule(activityScenarioRule) + .around(screenLockRule) + .around(lockStateTrackingRule) + .around(trustAgentRule) + + @Before + fun setUp() { + trustManager.registerTrustListener(trustListener) + } + + @Test + fun successfulUnlockAttempt_allowsTrustAgentToStart() = + runUnlockAttemptTest(enableAndVerifyTrustAgent = false, managingTrust = false) { + trustAgentRule.enableTrustAgent() + + triggerSuccessfulUnlock() + + trustAgentRule.verifyAgentIsRunning(MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START) + } + + @Test + fun successfulUnlockAttempt_notifiesTrustAgent() = + runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) { + val oldSuccessfulCount = agent.successfulUnlockCallCount + val oldFailedCount = agent.failedUnlockCallCount + + triggerSuccessfulUnlock() + + assertThat(agent.successfulUnlockCallCount).isEqualTo(oldSuccessfulCount + 1) + assertThat(agent.failedUnlockCallCount).isEqualTo(oldFailedCount) + } + + @Test + fun successfulUnlockAttempt_notifiesTrustListenerOfManagedTrust() = + runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) { + val oldTrustManagedChangedCount = trustListener.onTrustManagedChangedCount[userId] ?: 0 + + triggerSuccessfulUnlock() + + assertThat(trustListener.onTrustManagedChangedCount[userId] ?: 0).isEqualTo( + oldTrustManagedChangedCount + 1 + ) + } + + @Test + fun failedUnlockAttempt_doesNotAllowTrustAgentToStart() = + runUnlockAttemptTest(enableAndVerifyTrustAgent = false, managingTrust = false) { + trustAgentRule.enableTrustAgent() + + triggerFailedUnlock() + + trustAgentRule.ensureAgentIsNotRunning(MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START) + } + + @Test + fun failedUnlockAttempt_notifiesTrustAgent() = + runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) { + val oldSuccessfulCount = agent.successfulUnlockCallCount + val oldFailedCount = agent.failedUnlockCallCount + + triggerFailedUnlock() + + assertThat(agent.successfulUnlockCallCount).isEqualTo(oldSuccessfulCount) + assertThat(agent.failedUnlockCallCount).isEqualTo(oldFailedCount + 1) + } + + @Test + fun failedUnlockAttempt_doesNotNotifyTrustListenerOfManagedTrust() = + runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) { + val oldTrustManagedChangedCount = trustListener.onTrustManagedChangedCount[userId] ?: 0 + + triggerFailedUnlock() + + assertThat(trustListener.onTrustManagedChangedCount[userId] ?: 0).isEqualTo( + oldTrustManagedChangedCount + ) + } + + private fun runUnlockAttemptTest( + enableAndVerifyTrustAgent: Boolean, + managingTrust: Boolean, + testBlock: () -> Unit, + ) { + if (enableAndVerifyTrustAgent) { + Log.i(TAG, "Triggering successful unlock") + triggerSuccessfulUnlock() + Log.i(TAG, "Enabling and waiting for trust agent") + trustAgentRule.enableAndVerifyTrustAgentIsRunning( + MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START + ) + Log.i(TAG, "Managing trust: $managingTrust") + agent.setManagingTrust(managingTrust) + await() + } + testBlock() + } + + private fun triggerSuccessfulUnlock() { + screenLockRule.successfulScreenLockAttempt() + if (!shouldTrustManagerListenForPrimaryAuth()) { + trustAgentRule.reportSuccessfulUnlock() + } + await() + } + + private fun triggerFailedUnlock() { + screenLockRule.failedScreenLockAttempt() + if (!shouldTrustManagerListenForPrimaryAuth()) { + trustAgentRule.reportFailedUnlock() + } + await() + } + + companion object { + private const val TAG = "UnlockAttemptTest" + private fun await(millis: Long = 500) = Thread.sleep(millis) + private const val MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START = 10000L + } +} + +class UnlockAttemptTrustAgent : BaseTrustAgentService() { + var successfulUnlockCallCount: Long = 0 + private set + var failedUnlockCallCount: Long = 0 + private set + + override fun onUnlockAttempt(successful: Boolean) { + super.onUnlockAttempt(successful) + if (successful) { + successfulUnlockCallCount++ + } else { + failedUnlockCallCount++ + } + } +} + +private class UnlockAttemptTrustListener : TestTrustListener() { + var enabledTrustAgentsChangedCount = mutableMapOf<Int, Int>() + var onTrustManagedChangedCount = mutableMapOf<Int, Int>() + + override fun onEnabledTrustAgentsChanged(userId: Int) { + enabledTrustAgentsChangedCount.compute(userId) { _: Int, curr: Int? -> + if (curr == null) 0 else curr + 1 + } + } + + data class TrustChangedParams( + val enabled: Boolean, + val newlyUnlocked: Boolean, + val userId: Int, + val flags: Int, + val trustGrantedMessages: MutableList<String>? + ) + + val onTrustChangedCalls = mutableListOf<TrustChangedParams>() + + override fun onTrustChanged( + enabled: Boolean, + newlyUnlocked: Boolean, + userId: Int, + flags: Int, + trustGrantedMessages: MutableList<String> + ) { + onTrustChangedCalls += TrustChangedParams( + enabled, newlyUnlocked, userId, flags, trustGrantedMessages + ) + } + + override fun onTrustManagedChanged(enabled: Boolean, userId: Int) { + onTrustManagedChangedCount.compute(userId) { _: Int, curr: Int? -> + if (curr == null) 0 else curr + 1 + } + } +} diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt index f1edca3ff86e..1ccdcc623c5b 100644 --- a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt +++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt @@ -24,6 +24,8 @@ import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.uiautomator.UiDevice import com.android.internal.widget.LockPatternUtils +import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED +import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN import com.android.internal.widget.LockscreenCredential import com.google.common.truth.Truth.assertWithMessage import org.junit.rules.TestRule @@ -32,13 +34,18 @@ import org.junit.runners.model.Statement /** * Sets a screen lock on the device for the duration of the test. + * + * @param requireStrongAuth Whether a strong auth is required at the beginning. + * If true, trust agents will not be available until the user verifies their credentials. */ -class ScreenLockRule : TestRule { +class ScreenLockRule(val requireStrongAuth: Boolean = false) : TestRule { private val context: Context = getApplicationContext() + private val userId = context.userId private val uiDevice = UiDevice.getInstance(getInstrumentation()) private val windowManager = checkNotNull(WindowManagerGlobal.getWindowManagerService()) private val lockPatternUtils = LockPatternUtils(context) private var instantLockSavedValue = false + private var strongAuthSavedValue: Int = 0 override fun apply(base: Statement, description: Description) = object : Statement() { override fun evaluate() { @@ -46,10 +53,12 @@ class ScreenLockRule : TestRule { dismissKeyguard() setScreenLock() setLockOnPowerButton() + configureStrongAuthState() try { base.evaluate() } finally { + restoreStrongAuthState() removeScreenLock() revertLockOnPowerButton() dismissKeyguard() @@ -57,6 +66,22 @@ class ScreenLockRule : TestRule { } } + private fun configureStrongAuthState() { + strongAuthSavedValue = lockPatternUtils.getStrongAuthForUser(userId) + if (requireStrongAuth) { + Log.d(TAG, "Triggering strong auth due to simulated lockdown") + lockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, userId) + wait("strong auth required after lockdown") { + lockPatternUtils.getStrongAuthForUser(userId) == + STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN + } + } + } + + private fun restoreStrongAuthState() { + lockPatternUtils.requireStrongAuth(strongAuthSavedValue, userId) + } + private fun verifyNoScreenLockAlreadySet() { assertWithMessage("Screen Lock must not already be set on device") .that(lockPatternUtils.isSecure(context.userId)) @@ -82,6 +107,22 @@ class ScreenLockRule : TestRule { } } + fun successfulScreenLockAttempt() { + lockPatternUtils.verifyCredential(LockscreenCredential.createPin(PIN), context.userId, 0) + lockPatternUtils.userPresent(context.userId) + wait("strong auth not required") { + lockPatternUtils.getStrongAuthForUser(context.userId) == STRONG_AUTH_NOT_REQUIRED + } + } + + fun failedScreenLockAttempt() { + lockPatternUtils.verifyCredential( + LockscreenCredential.createPin(WRONG_PIN), + context.userId, + 0 + ) + } + private fun setScreenLock() { lockPatternUtils.setLockCredential( LockscreenCredential.createPin(PIN), @@ -121,5 +162,6 @@ class ScreenLockRule : TestRule { companion object { private const val TAG = "ScreenLockRule" private const val PIN = "0000" + private const val WRONG_PIN = "0001" } } diff --git a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt index 18bc029b6845..404c6d968b3a 100644 --- a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt +++ b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt @@ -20,14 +20,15 @@ import android.app.trust.TrustManager import android.content.ComponentName import android.content.Context import android.trust.BaseTrustAgentService +import android.trust.test.lib.TrustAgentRule.Companion.invoke import android.util.Log import androidx.test.core.app.ApplicationProvider.getApplicationContext import com.android.internal.widget.LockPatternUtils import com.google.common.truth.Truth.assertWithMessage +import kotlin.reflect.KClass import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement -import kotlin.reflect.KClass /** * Enables a trust agent and causes the system service to bind to it. @@ -37,7 +38,9 @@ import kotlin.reflect.KClass * @constructor Creates the rule. Do not use; instead, use [invoke]. */ class TrustAgentRule<T : BaseTrustAgentService>( - private val serviceClass: KClass<T> + private val serviceClass: KClass<T>, + private val startUnlocked: Boolean, + private val startEnabled: Boolean, ) : TestRule { private val context: Context = getApplicationContext() private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager @@ -48,11 +51,18 @@ class TrustAgentRule<T : BaseTrustAgentService>( override fun apply(base: Statement, description: Description) = object : Statement() { override fun evaluate() { verifyTrustServiceRunning() - unlockDeviceWithCredential() - enableTrustAgent() + if (startUnlocked) { + reportSuccessfulUnlock() + } else { + Log.i(TAG, "Trust manager not starting in unlocked state") + } try { - verifyAgentIsRunning() + if (startEnabled) { + enableAndVerifyTrustAgentIsRunning() + } else { + Log.i(TAG, "Trust agent ${serviceClass.simpleName} not enabled") + } base.evaluate() } finally { disableTrustAgent() @@ -64,12 +74,22 @@ class TrustAgentRule<T : BaseTrustAgentService>( assertWithMessage("Trust service is not running").that(trustManager).isNotNull() } - private fun unlockDeviceWithCredential() { - Log.d(TAG, "Unlocking device with credential") + fun reportSuccessfulUnlock() { + Log.i(TAG, "Reporting successful unlock") trustManager.reportUnlockAttempt(true, context.userId) } - private fun enableTrustAgent() { + fun reportFailedUnlock() { + Log.i(TAG, "Reporting failed unlock") + trustManager.reportUnlockAttempt(false, context.userId) + } + + fun enableAndVerifyTrustAgentIsRunning(maxWait: Long = 30000L) { + enableTrustAgent() + verifyAgentIsRunning(maxWait) + } + + fun enableTrustAgent() { val componentName = ComponentName(context, serviceClass.java) val userId = context.userId Log.i(TAG, "Enabling trust agent ${componentName.flattenToString()} for user $userId") @@ -79,12 +99,18 @@ class TrustAgentRule<T : BaseTrustAgentService>( lockPatternUtils.setEnabledTrustAgents(agents, userId) } - private fun verifyAgentIsRunning() { - wait("${serviceClass.simpleName} to be running") { + fun verifyAgentIsRunning(maxWait: Long = 30000L) { + wait("${serviceClass.simpleName} to be running", maxWait) { BaseTrustAgentService.instance(serviceClass) != null } } + fun ensureAgentIsNotRunning(window: Long = 30000L) { + ensure("${serviceClass.simpleName} is not running", window) { + BaseTrustAgentService.instance(serviceClass) == null + } + } + private fun disableTrustAgent() { val componentName = ComponentName(context, serviceClass.java) val userId = context.userId @@ -97,13 +123,23 @@ class TrustAgentRule<T : BaseTrustAgentService>( companion object { /** - * Creates a new rule for the specified agent class. Example usage: + * Creates a new rule for the specified agent class. Starts with the device unlocked and + * the trust agent enabled. Example usage: * ``` * @get:Rule val rule = TrustAgentRule<MyTestAgent>() * ``` + * + * Also supports setting different device lock and trust agent enablement states: + * ``` + * @get:Rule val rule = TrustAgentRule<MyTestAgent>(startUnlocked = false, startEnabled = false) + * ``` */ - inline operator fun <reified T : BaseTrustAgentService> invoke() = - TrustAgentRule(T::class) + inline operator fun <reified T : BaseTrustAgentService> invoke( + startUnlocked: Boolean = true, + startEnabled: Boolean = true, + ) = + TrustAgentRule(T::class, startUnlocked, startEnabled) + private const val TAG = "TrustAgentRule" } diff --git a/tests/TrustTests/src/android/trust/test/lib/utils.kt b/tests/TrustTests/src/android/trust/test/lib/Utils.kt index e047202f6740..3b32b47a6160 100644 --- a/tests/TrustTests/src/android/trust/test/lib/utils.kt +++ b/tests/TrustTests/src/android/trust/test/lib/Utils.kt @@ -39,7 +39,7 @@ internal fun wait( ) { var waited = 0L var count = 0 - while (!conditionFunction.invoke(count)) { + while (!conditionFunction(count)) { assertWithMessage("Condition exceeded maximum wait time of $maxWait ms: $description") .that(waited <= maxWait) .isTrue() @@ -49,3 +49,34 @@ internal fun wait( Thread.sleep(rate) } } + +/** + * Ensures that [conditionFunction] is true with a failed assertion if it is not within [window] + * ms. + * + * The condition function can perform additional logic (for example, logging or attempting to make + * the condition become true). + * + * @param conditionFunction function which takes the attempt count & returns whether the condition + * is met + */ +internal fun ensure( + description: String? = null, + window: Long = 30000L, + rate: Long = 50L, + conditionFunction: (count: Int) -> Boolean +) { + var waited = 0L + var count = 0 + while (waited <= window) { + assertWithMessage("Condition failed within $window ms: $description").that( + conditionFunction( + count + ) + ).isTrue() + waited += rate + count++ + Log.i(TAG, "Ensuring $description ($waited/$window) #$count") + Thread.sleep(rate) + } +} diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 031dd5bb139c..9b8c3b3d549c 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -836,6 +836,28 @@ int CompileCommand::Action(const std::vector<std::string>& args) { return 1; } + // Parse the feature flag values. An argument that starts with '@' points to a file to read flag + // values from. + std::vector<std::string> all_feature_flags_args; + for (const std::string& arg : feature_flags_args_) { + if (util::StartsWith(arg, "@")) { + const std::string path = arg.substr(1, arg.size() - 1); + std::string error; + if (!file::AppendArgsFromFile(path, &all_feature_flags_args, &error)) { + context.GetDiagnostics()->Error(android::DiagMessage(path) << error); + return 1; + } + } else { + all_feature_flags_args.push_back(arg); + } + } + + for (const std::string& arg : all_feature_flags_args) { + if (!ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) { + return 1; + } + } + return Compile(&context, file_collection.get(), archive_writer.get(), options_); } diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h index 61c5b60adb76..70c8791524c8 100644 --- a/tools/aapt2/cmd/Compile.h +++ b/tools/aapt2/cmd/Compile.h @@ -24,6 +24,7 @@ #include "Command.h" #include "ResourceTable.h" #include "androidfw/IDiagnostics.h" +#include "cmd/Util.h" #include "format/Archive.h" #include "process/IResourceTableConsumer.h" @@ -45,6 +46,7 @@ struct CompileOptions { bool preserve_visibility_of_styleables = false; bool verbose = false; std::optional<std::string> product_; + FeatureFlagValues feature_flag_values; }; /** Parses flags and compiles resources to be used in linking. */ @@ -92,6 +94,12 @@ class CompileCommand : public Command { "Leave only resources specific to the given product. All " "other resources (including defaults) are removed.", &options_.product_); + AddOptionalFlagList("--feature-flags", + "Specify the values of feature flags. The pairs in the argument\n" + "are separated by ',' the name is separated from the value by '='.\n" + "The name can have a suffix of ':ro' to indicate it is read only." + "Example: \"flag1=true,flag2:ro=false,flag3=\" (flag3 has no given value).", + &feature_flags_args_); } int Action(const std::vector<std::string>& args) override; @@ -101,6 +109,7 @@ class CompileCommand : public Command { CompileOptions options_; std::optional<std::string> visibility_; std::optional<std::string> trace_folder_; + std::vector<std::string> feature_flags_args_; }; int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 8fe414f4f660..2f17853718ec 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -332,8 +332,9 @@ class LinkCommand : public Command { AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); AddOptionalFlagList("--feature-flags", "Specify the values of feature flags. The pairs in the argument\n" - "are separated by ',' and the name is separated from the value by '='.\n" - "Example: \"flag1=true,flag2=false,flag3=\" (flag3 has no given value).", + "are separated by ',' the name is separated from the value by '='.\n" + "The name can have a suffix of ':ro' to indicate it is read only." + "Example: \"flag1=true,flag2:ro=false,flag3=\" (flag3 has no given value).", &feature_flags_args_); AddOptionalSwitch("--non-updatable-system", "Mark the app as a non-updatable system app. This inserts\n" diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp index 678d84628015..7739171b347f 100644 --- a/tools/aapt2/cmd/Util.cpp +++ b/tools/aapt2/cmd/Util.cpp @@ -128,7 +128,7 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, if (parts.size() > 2) { diag->Error(android::DiagMessage() << "Invalid feature flag and optional value '" << flag_and_value - << "'. Must be in the format 'flag_name[=true|false]"); + << "'. Must be in the format 'flag_name[:ro][=true|false]"); return false; } @@ -138,6 +138,28 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, return false; } + std::vector<std::string> name_parts = util::Split(flag_name, ':'); + if (name_parts.size() > 2) { + diag->Error(android::DiagMessage() + << "Invalid feature flag and optional value '" << flag_and_value + << "'. Must be in the format 'flag_name[:READ_ONLY|READ_WRITE][=true|false]"); + return false; + } + flag_name = name_parts[0]; + bool read_only = false; + if (name_parts.size() == 2) { + if (name_parts[1] == "ro" || name_parts[1] == "READ_ONLY") { + read_only = true; + } else if (name_parts[1] == "READ_WRITE") { + read_only = false; + } else { + diag->Error(android::DiagMessage() + << "Invalid feature flag and optional value '" << flag_and_value + << "'. Must be in the format 'flag_name[:READ_ONLY|READ_WRITE][=true|false]"); + return false; + } + } + std::optional<bool> flag_value = {}; if (parts.size() == 2) { StringPiece str_flag_value = util::TrimWhitespace(parts[1]); @@ -151,13 +173,13 @@ bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, } } - if (auto [it, inserted] = - out_feature_flag_values->try_emplace(std::string(flag_name), flag_value); + auto ffp = FeatureFlagProperties{read_only, flag_value}; + if (auto [it, inserted] = out_feature_flag_values->try_emplace(std::string(flag_name), ffp); !inserted) { // We are allowing the same flag to appear multiple times, last value wins. diag->Note(android::DiagMessage() << "Value for feature flag '" << flag_name << "' was given more than once"); - it->second = flag_value; + it->second = ffp; } } return true; diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h index 9ece5dd4d720..6b8813b34082 100644 --- a/tools/aapt2/cmd/Util.h +++ b/tools/aapt2/cmd/Util.h @@ -37,7 +37,17 @@ namespace aapt { -using FeatureFlagValues = std::map<std::string, std::optional<bool>, std::less<>>; +struct FeatureFlagProperties { + bool read_only; + std::optional<bool> enabled; + + FeatureFlagProperties(bool ro, std::optional<bool> e) : read_only(ro), enabled(e) { + } + + bool operator==(const FeatureFlagProperties&) const = default; +}; + +using FeatureFlagValues = std::map<std::string, FeatureFlagProperties, std::less<>>; // Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc). // Returns Nothing and logs a human friendly error message if the string was not legal. diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp index 723d87ed0af3..78183409ad8f 100644 --- a/tools/aapt2/cmd/Util_test.cpp +++ b/tools/aapt2/cmd/Util_test.cpp @@ -383,21 +383,25 @@ TEST(UtilTest, ParseFeatureFlagsParameter_InvalidValue) { TEST(UtilTest, ParseFeatureFlagsParameter_DuplicateFlag) { auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics(); FeatureFlagValues feature_flag_values; - ASSERT_TRUE( - ParseFeatureFlagsParameter("foo=true,bar=true,foo=false", diagnostics, &feature_flag_values)); - EXPECT_THAT(feature_flag_values, UnorderedElementsAre(Pair("foo", std::optional<bool>(false)), - Pair("bar", std::optional<bool>(true)))); + ASSERT_TRUE(ParseFeatureFlagsParameter("foo=true,bar:READ_WRITE=true,foo:ro=false", diagnostics, + &feature_flag_values)); + EXPECT_THAT( + feature_flag_values, + UnorderedElementsAre(Pair("foo", FeatureFlagProperties{true, std::optional<bool>(false)}), + Pair("bar", FeatureFlagProperties{false, std::optional<bool>(true)}))); } TEST(UtilTest, ParseFeatureFlagsParameter_Valid) { auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics(); FeatureFlagValues feature_flag_values; - ASSERT_TRUE(ParseFeatureFlagsParameter("foo= true, bar =FALSE,baz=, quux", diagnostics, - &feature_flag_values)); - EXPECT_THAT(feature_flag_values, - UnorderedElementsAre(Pair("foo", std::optional<bool>(true)), - Pair("bar", std::optional<bool>(false)), - Pair("baz", std::nullopt), Pair("quux", std::nullopt))); + ASSERT_TRUE(ParseFeatureFlagsParameter("foo:READ_ONLY= true, bar:ro =FALSE,baz:READ_WRITE=, quux", + diagnostics, &feature_flag_values)); + EXPECT_THAT( + feature_flag_values, + UnorderedElementsAre(Pair("foo", FeatureFlagProperties{true, std::optional<bool>(true)}), + Pair("bar", FeatureFlagProperties{true, std::optional<bool>(false)}), + Pair("baz", FeatureFlagProperties{false, std::nullopt}), + Pair("quux", FeatureFlagProperties{false, std::nullopt}))); } TEST (UtilTest, AdjustSplitConstraintsForMinSdk) { diff --git a/tools/aapt2/link/FeatureFlagsFilter.cpp b/tools/aapt2/link/FeatureFlagsFilter.cpp index fdf3f74d4e18..9d40db521e13 100644 --- a/tools/aapt2/link/FeatureFlagsFilter.cpp +++ b/tools/aapt2/link/FeatureFlagsFilter.cpp @@ -63,12 +63,11 @@ class FlagsVisitor : public xml::Visitor { flag_name = flag_name.substr(1); } - if (auto it = feature_flag_values_.find(std::string(flag_name)); - it != feature_flag_values_.end()) { - if (it->second.has_value()) { + if (auto it = feature_flag_values_.find(flag_name); it != feature_flag_values_.end()) { + if (it->second.enabled.has_value()) { if (options_.remove_disabled_elements) { // Remove if flag==true && attr=="!flag" (negated) OR flag==false && attr=="flag" - return *it->second == negated; + return *it->second.enabled == negated; } } else if (options_.flags_must_have_value) { diagnostics_->Error(android::DiagMessage(node->line_number) diff --git a/tools/aapt2/link/FeatureFlagsFilter_test.cpp b/tools/aapt2/link/FeatureFlagsFilter_test.cpp index 53086cc30f18..2db2899e716c 100644 --- a/tools/aapt2/link/FeatureFlagsFilter_test.cpp +++ b/tools/aapt2/link/FeatureFlagsFilter_test.cpp @@ -48,7 +48,7 @@ TEST(FeatureFlagsFilterTest, NoFeatureFlagAttributes) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" /> </manifest>)EOF", - {{"flag", false}}); + {{"flag", FeatureFlagProperties{false, false}}}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -60,7 +60,7 @@ TEST(FeatureFlagsFilterTest, RemoveElementWithDisabledFlag) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag="flag" /> </manifest>)EOF", - {{"flag", false}}); + {{"flag", FeatureFlagProperties{false, false}}}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -73,7 +73,7 @@ TEST(FeatureFlagsFilterTest, RemoveElementWithNegatedEnabledFlag) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag="!flag" /> </manifest>)EOF", - {{"flag", true}}); + {{"flag", FeatureFlagProperties{false, true}}}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -86,7 +86,7 @@ TEST(FeatureFlagsFilterTest, KeepElementWithEnabledFlag) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag="flag" /> </manifest>)EOF", - {{"flag", true}}); + {{"flag", FeatureFlagProperties{false, true}}}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -102,7 +102,7 @@ TEST(FeatureFlagsFilterTest, SideBySideEnabledAndDisabled) { <permission android:name="FOO" android:featureFlag="flag" android:protectionLevel="dangerous" /> </manifest>)EOF", - {{"flag", true}}); + {{"flag", FeatureFlagProperties{false, true}}}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -123,7 +123,7 @@ TEST(FeatureFlagsFilterTest, RemoveDeeplyNestedElement) { </activity> </application> </manifest>)EOF", - {{"flag", true}}); + {{"flag", FeatureFlagProperties{false, true}}}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -145,7 +145,7 @@ TEST(FeatureFlagsFilterTest, KeepDeeplyNestedElement) { </activity> </application> </manifest>)EOF", - {{"flag", true}}); + {{"flag", FeatureFlagProperties{false, true}}}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -162,7 +162,7 @@ TEST(FeatureFlagsFilterTest, FailOnEmptyFeatureFlagAttribute) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag=" " /> </manifest>)EOF", - {{"flag", false}}); + {{"flag", FeatureFlagProperties{false, false}}}); ASSERT_THAT(doc, IsNull()); } @@ -171,7 +171,7 @@ TEST(FeatureFlagsFilterTest, FailOnFlagWithNoGivenValue) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag="flag" /> </manifest>)EOF", - {{"flag", std::nullopt}}); + {{"flag", FeatureFlagProperties{false, std::nullopt}}}); ASSERT_THAT(doc, IsNull()); } @@ -180,7 +180,7 @@ TEST(FeatureFlagsFilterTest, FailOnUnrecognizedFlag) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag="unrecognized" /> </manifest>)EOF", - {{"flag", true}}); + {{"flag", FeatureFlagProperties{false, true}}}); ASSERT_THAT(doc, IsNull()); } @@ -190,7 +190,7 @@ TEST(FeatureFlagsFilterTest, FailOnMultipleValidationErrors) { <permission android:name="FOO" android:featureFlag="bar" /> <permission android:name="FOO" android:featureFlag="unrecognized" /> </manifest>)EOF", - {{"flag", std::nullopt}}); + {{"flag", FeatureFlagProperties{false, std::nullopt}}}); ASSERT_THAT(doc, IsNull()); } @@ -199,7 +199,8 @@ TEST(FeatureFlagsFilterTest, OptionRemoveDisabledElementsIsFalse) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag="flag" /> </manifest>)EOF", - {{"flag", false}}, {.remove_disabled_elements = false}); + {{"flag", FeatureFlagProperties{false, false}}}, + {.remove_disabled_elements = false}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -212,7 +213,8 @@ TEST(FeatureFlagsFilterTest, OptionFlagsMustHaveValueIsFalse) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag="flag" /> </manifest>)EOF", - {{"flag", std::nullopt}}, {.flags_must_have_value = false}); + {{"flag", FeatureFlagProperties{false, std::nullopt}}}, + {.flags_must_have_value = false}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); @@ -225,7 +227,8 @@ TEST(FeatureFlagsFilterTest, OptionFailOnUnrecognizedFlagsIsFalse) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <permission android:name="FOO" android:featureFlag="unrecognized" /> </manifest>)EOF", - {{"flag", true}}, {.fail_on_unrecognized_flags = false}); + {{"flag", FeatureFlagProperties{false, true}}}, + {.fail_on_unrecognized_flags = false}); ASSERT_THAT(doc, NotNull()); auto root = doc->root.get(); ASSERT_THAT(root, NotNull()); diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp index 02e4beaed949..8ae55b8868c3 100644 --- a/tools/aapt2/util/Files.cpp +++ b/tools/aapt2/util/Files.cpp @@ -189,7 +189,7 @@ void AppendPath(std::string* base, StringPiece part) { base->append(part.data(), part.size()); } -std::string BuildPath(std::vector<const StringPiece>&& args) { +std::string BuildPath(const std::vector<StringPiece>& args) { if (args.empty()) { return ""; } diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h index 42eeaf2d2e2a..c1a42446ec3b 100644 --- a/tools/aapt2/util/Files.h +++ b/tools/aapt2/util/Files.h @@ -60,7 +60,7 @@ FileType GetFileType(const std::string& path); void AppendPath(std::string* base, android::StringPiece part); // Concatenates the list of paths and separates each part with the directory separator. -std::string BuildPath(std::vector<const android::StringPiece>&& args); +std::string BuildPath(const std::vector<android::StringPiece>& args); // Makes all the directories in `path`. The last element in the path is interpreted as a directory. bool mkdirs(const std::string& path); diff --git a/tools/lint/OWNERS b/tools/lint/OWNERS index 33e237d306fc..8e4569ee2a30 100644 --- a/tools/lint/OWNERS +++ b/tools/lint/OWNERS @@ -1,4 +1,5 @@ -brufino@google.com +mattgilbride@google.com +azharaa@google.com jsharkey@google.com per-file *CallingSettingsNonUserGetterMethods* = file:/packages/SettingsProvider/OWNERS diff --git a/tools/lint/fix/README.md b/tools/lint/fix/README.md index a5ac2be1c18a..18bda9287a50 100644 --- a/tools/lint/fix/README.md +++ b/tools/lint/fix/README.md @@ -6,7 +6,7 @@ Inspiration: go/refactor-the-platform-with-lint\ It's a python script that runs the framework linter, and then (optionally) copies modified files back into the source tree.\ -Why python, you ask? Because python is cool ¯\_(ツ)_/¯. +Why python, you ask? Because python is cool ¯\\\_(ツ)\_/¯. Incidentally, this exposes a much simpler way to run individual lint checks against individual modules, so it's useful beyond applying fixes. @@ -15,7 +15,7 @@ against individual modules, so it's useful beyond applying fixes. Lint is not allowed to modify source files directly via lint's `--apply-suggestions` flag. As a compromise, soong zips up the (potentially) modified sources and leaves them in an intermediate -directory. This script runs the lint, unpacks those files, and copies them back into the tree. +directory. This script runs the lint, unpacks those files, and copies them back into the tree. ## How do I run it? **WARNING: You probably want to commit/stash any changes to your working tree before doing this...** |