summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--Android.mk65
-rw-r--r--TEST_MAPPING25
-rw-r--r--apex/jobscheduler/service/Android.bp2
-rw-r--r--core/api/current.txt7
-rw-r--r--core/api/module-lib-current.txt1
-rw-r--r--core/java/Android.bp3
-rw-r--r--core/java/android/accessibilityservice/OWNERS10
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/ActivityThread.java7
-rw-r--r--core/java/android/app/OWNERS1
-rw-r--r--core/java/android/app/RESOURCES_OWNERS6
-rw-r--r--core/java/android/app/network-policy.aconfig11
-rw-r--r--core/java/android/content/rollback/OWNERS4
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java9
-rw-r--r--core/java/android/net/vcn/VcnManager.java7
-rw-r--r--core/java/android/net/vcn/flags.aconfig14
-rw-r--r--core/java/android/service/media/OWNERS8
-rw-r--r--core/java/android/service/voice/OWNERS1
-rw-r--r--core/java/android/view/OWNERS2
-rw-r--r--core/java/android/view/accessibility/OWNERS27
-rw-r--r--core/java/com/android/internal/accessibility/OWNERS10
-rw-r--r--core/java/com/android/internal/accessibility/common/MagnificationConstants.java7
-rw-r--r--core/java/com/android/internal/net/ConnectivityBlobStore.java173
-rw-r--r--core/jni/OWNERS3
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/xml/sms_short_codes.xml26
-rw-r--r--core/tests/bugreports/OWNERS2
-rw-r--r--core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java156
-rw-r--r--core/tests/coretests/src/com/android/internal/net/OWNERS1
-rw-r--r--data/etc/OWNERS1
-rw-r--r--data/fonts/fonts.xml10
-rw-r--r--keystore/java/android/security/AndroidKeyStoreMaintenance.java14
-rw-r--r--keystore/java/android/security/KeyStore.java16
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java72
-rw-r--r--keystore/java/android/security/keystore/KeyInfo.java2
-rw-r--r--keystore/java/android/security/keystore/KeyProtection.java70
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java14
-rw-r--r--keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java3
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.h2
-rw-r--r--media/OWNERS8
-rw-r--r--media/java/android/media/AudioDescriptor.java2
-rw-r--r--media/java/android/media/AudioManager.java2
-rw-r--r--media/java/android/media/BluetoothProfileConnectionInfo.java12
-rw-r--r--media/java/android/media/MediaCas.java149
-rw-r--r--media/java/android/media/MediaCodec.java4
-rw-r--r--media/java/android/media/MediaCodecInfo.java9
-rw-r--r--media/java/android/media/MediaFormat.java65
-rw-r--r--media/java/android/media/browse/OWNERS8
-rw-r--r--media/java/android/media/session/OWNERS8
-rw-r--r--media/jni/soundpool/android_media_SoundPool.cpp13
-rw-r--r--nfc/Android.bp3
-rw-r--r--packages/CrashRecovery/OWNERS4
-rw-r--r--packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java235
-rw-r--r--packages/CrashRecovery/services/java/com/android/server/RescueParty.java344
-rw-r--r--packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java4
-rw-r--r--packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java115
-rw-r--r--packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java (renamed from packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java)2
-rw-r--r--packages/CrashRecovery/services/java/com/android/utils/FileUtils.java128
-rw-r--r--packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java (renamed from packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java)2
-rw-r--r--packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java188
-rw-r--r--packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java118
-rw-r--r--packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java4
-rw-r--r--packages/SystemUI/Android.bp6
-rw-r--r--packages/SystemUI/animation/Android.bp4
-rw-r--r--packages/SystemUI/shared/Android.bp3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java4
-rw-r--r--packages/Tethering/OWNERS1
-rw-r--r--services/Android.bp1
-rw-r--r--services/accessibility/OWNERS15
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java5
-rw-r--r--services/backup/BACKUP_OWNERS5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/LmkdStatsReporter.java3
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java4
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java2
-rw-r--r--services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java129
-rw-r--r--services/core/java/com/android/server/crashrecovery/OWNERS3
-rw-r--r--services/core/java/com/android/server/inputmethod/LocaleUtils.java28
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java31
-rw-r--r--services/core/java/com/android/server/net/OWNERS1
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/InstallRequest.java3
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java9
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java2
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java2
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java1
-rw-r--r--services/core/java/com/android/server/rollback/OWNERS4
-rw-r--r--services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java9
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java24
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java10
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java13
-rw-r--r--services/core/java/com/android/server/wm/OWNERS2
-rw-r--r--services/core/jni/com_android_server_am_OomConnection.cpp6
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java4
-rw-r--r--services/proguard.flags5
-rw-r--r--services/tests/PackageManagerServiceTests/server/Android.bp2
-rw-r--r--services/tests/VpnTests/Android.bp10
-rw-r--r--services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java324
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/rollback/OWNERS4
-rw-r--r--services/tests/servicestests/Android.bp86
-rw-r--r--services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING6
-rw-r--r--services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING6
-rw-r--r--services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING6
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/om/TEST_MAPPING6
-rw-r--r--services/tests/servicestests/src/com/android/server/os/TEST_MAPPING6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING22
-rw-r--r--services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java1
-rw-r--r--services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java2
-rw-r--r--test-base/Android.bp39
-rw-r--r--test-base/hiddenapi/Android.bp7
-rw-r--r--test-junit/Android.bp53
-rw-r--r--test-junit/src/junit/MODULE_LICENSE_CPL (renamed from test-base/src/junit/MODULE_LICENSE_CPL)0
-rw-r--r--test-junit/src/junit/README.android (renamed from test-base/src/junit/README.android)0
-rw-r--r--test-junit/src/junit/cpl-v10.html (renamed from test-base/src/junit/cpl-v10.html)0
-rw-r--r--test-junit/src/junit/framework/Assert.java (renamed from test-base/src/junit/framework/Assert.java)0
-rw-r--r--test-junit/src/junit/framework/AssertionFailedError.java (renamed from test-base/src/junit/framework/AssertionFailedError.java)0
-rw-r--r--test-junit/src/junit/framework/ComparisonCompactor.java (renamed from test-base/src/junit/framework/ComparisonCompactor.java)0
-rw-r--r--test-junit/src/junit/framework/ComparisonFailure.java (renamed from test-base/src/junit/framework/ComparisonFailure.java)0
-rw-r--r--test-junit/src/junit/framework/Protectable.java (renamed from test-base/src/junit/framework/Protectable.java)0
-rw-r--r--test-junit/src/junit/framework/Test.java (renamed from test-base/src/junit/framework/Test.java)0
-rw-r--r--test-junit/src/junit/framework/TestCase.java (renamed from test-base/src/junit/framework/TestCase.java)0
-rw-r--r--test-junit/src/junit/framework/TestFailure.java (renamed from test-base/src/junit/framework/TestFailure.java)0
-rw-r--r--test-junit/src/junit/framework/TestListener.java (renamed from test-base/src/junit/framework/TestListener.java)0
-rw-r--r--test-junit/src/junit/framework/TestResult.java (renamed from test-base/src/junit/framework/TestResult.java)0
-rw-r--r--test-junit/src/junit/framework/TestSuite.java (renamed from test-base/src/junit/framework/TestSuite.java)0
-rw-r--r--test-junit/src/junit/runner/BaseTestRunner.java (renamed from test-runner/src/junit/runner/BaseTestRunner.java)0
-rw-r--r--test-junit/src/junit/runner/StandardTestSuiteLoader.java (renamed from test-runner/src/junit/runner/StandardTestSuiteLoader.java)0
-rw-r--r--test-junit/src/junit/runner/TestRunListener.java (renamed from test-runner/src/junit/runner/TestRunListener.java)0
-rw-r--r--test-junit/src/junit/runner/TestSuiteLoader.java (renamed from test-runner/src/junit/runner/TestSuiteLoader.java)0
-rw-r--r--test-junit/src/junit/runner/Version.java (renamed from test-runner/src/junit/runner/Version.java)0
-rw-r--r--test-junit/src/junit/runner/package-info.java (renamed from test-runner/src/junit/runner/package-info.java)0
-rw-r--r--test-junit/src/junit/textui/ResultPrinter.java (renamed from test-runner/src/junit/textui/ResultPrinter.java)0
-rw-r--r--test-junit/src/junit/textui/TestRunner.java (renamed from test-runner/src/junit/textui/TestRunner.java)0
-rw-r--r--test-junit/src/junit/textui/package-info.java (renamed from test-runner/src/junit/textui/package-info.java)0
-rw-r--r--test-legacy/Android.bp38
-rw-r--r--test-legacy/Android.mk50
-rw-r--r--test-mock/Android.bp7
-rw-r--r--test-runner/Android.bp24
-rw-r--r--test-runner/src/junit/MODULE_LICENSE_CPL0
-rw-r--r--test-runner/src/junit/README.android11
-rw-r--r--test-runner/src/junit/cpl-v10.html125
-rw-r--r--test-runner/tests/Android.bp7
-rw-r--r--tests/PackageWatchdog/Android.bp2
-rw-r--r--tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java644
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java375
-rw-r--r--tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java17
-rw-r--r--tests/testables/OWNERS1
-rw-r--r--tests/vcn/Android.bp1
-rw-r--r--tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java19
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java29
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java16
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java33
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt25
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt19
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt25
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt19
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt25
170 files changed, 3963 insertions, 826 deletions
diff --git a/Android.bp b/Android.bp
index 80469d649649..900fba03daa7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -386,7 +386,6 @@ java_defaults {
// TODO(b/120066492): remove gps_debug and protolog.conf.json when the build
// system propagates "required" properly.
"gps_debug.conf",
- "protolog.conf.json.gz",
"framework-res",
// any install dependencies should go into framework-minus-apex-install-dependencies
// rather than here to avoid bloating incremental build time
diff --git a/Android.mk b/Android.mk
index e2c1ed8e9ddb..a126c52e2491 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,67 +15,6 @@
#
LOCAL_PATH := $(call my-dir)
-$(eval $(call declare-1p-copy-files,frameworks/base,.ogg))
-$(eval $(call declare-1p-copy-files,frameworks/base,.kl))
-$(eval $(call declare-1p-copy-files,frameworks/base,.kcm))
-$(eval $(call declare-1p-copy-files,frameworks/base,.idc))
-$(eval $(call declare-1p-copy-files,frameworks/base,dirty-image-objects))
-$(eval $(call declare-1p-copy-files,frameworks/base/config,))
-$(eval $(call declare-1p-copy-files,frameworks/native/data,))
-
-# Load framework-specific path mappings used later in the build.
-include $(LOCAL_PATH)/pathmap.mk
-
-# Build the master framework library.
-# The framework contains too many method references (>64K) for poor old DEX.
-# So we first build the framework as a monolithic static library then split it
-# up into smaller pieces.
-# ============================================================
-
-# embedded builds use nothing in frameworks/base
-ifneq ($(ANDROID_BUILD_EMBEDDED),true)
-
-# Copy AIDL files to be preprocessed and included in the SDK,
-# specified relative to the root of the build tree.
-# ============================================================
-include $(CLEAR_VARS)
-
-# sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
-# So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
-# $(OUT_DOCS)/offline-sdk.
-$(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip
- $(hide) rm -rf $(OUT_DOCS)/offline-sdk
- $(hide) mkdir -p $(OUT_DOCS)/offline-sdk
- ( unzip -qo $< -d $(OUT_DOCS)/offline-sdk && touch -f $@ ) || exit 1
-
-.PHONY: docs offline-sdk-docs
-docs offline-sdk-docs: $(OUT_DOCS)/offline-sdk-timestamp
-
-SDK_METADATA_DIR :=$= $(call intermediates-dir-for,PACKAGING,framework-doc-stubs-metadata,,COMMON)
-SDK_METADATA_FILES :=$= $(addprefix $(SDK_METADATA_DIR)/,\
- activity_actions.txt \
- broadcast_actions.txt \
- categories.txt \
- features.txt \
- service_actions.txt \
- widgets.txt)
-SDK_METADATA :=$= $(firstword $(SDK_METADATA_FILES))
-$(SDK_METADATA): .KATI_IMPLICIT_OUTPUTS := $(filter-out $(SDK_METADATA),$(SDK_METADATA_FILES))
-$(SDK_METADATA): $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/framework-doc-stubs-metadata.zip
- rm -rf $(SDK_METADATA_DIR)
- mkdir -p $(SDK_METADATA_DIR)
- unzip -DDqo $< -d $(SDK_METADATA_DIR)
-
-.PHONY: framework-doc-stubs
-framework-doc-stubs: $(SDK_METADATA)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
+# TODO: Empty this file after all subdirectories' Android.mk have been
+# converted to Android.bp to avoid using any newly added Android.mk.
include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
-
-endif # ANDROID_BUILD_EMBEDDED
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d59775f4060b..6d9756dddd4e 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -234,30 +234,5 @@
}
]
}
- ],
- "auto-features-postsubmit": [
- // Test tag for automotive feature targets. These are only running in postsubmit.
- // This tag is used in targeted test features testing to limit resource use.
- // TODO(b/256932212): this tag to be removed once the above is no longer in use.
- {
- "name": "FrameworksMockingServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.UserVisibilityMediatorSUSDTest"
- },
- {
- "include-filter": "com.android.server.pm.UserVisibilityMediatorMUMDTest"
- },
- {
- "include-filter": "com.android.server.pm.UserVisibilityMediatorMUPANDTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
]
}
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index 8b55e071e715..a654f7a2d974 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -20,7 +20,9 @@ java_library {
],
libs: [
+ "androidx.annotation_annotation",
"app-compat-annotations",
+ "error_prone_annotations",
"framework",
"services.core",
"unsupportedappusage",
diff --git a/core/api/current.txt b/core/api/current.txt
index 78ef5f14f37a..48949f8883bd 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -23419,6 +23419,13 @@ package android.media {
field public static final int VIDEO_ENCODING_STATISTICS_LEVEL_NONE = 0; // 0x0
}
+ @FlaggedApi("android.media.codec.region_of_interest") public static final class MediaFormat.QpOffsetRect {
+ ctor public MediaFormat.QpOffsetRect(@NonNull android.graphics.Rect, int);
+ method @NonNull public String flattenToString();
+ method @NonNull public static String flattenToString(@NonNull java.util.List<android.media.MediaFormat.QpOffsetRect>);
+ method public void set(@NonNull android.graphics.Rect, int);
+ }
+
public final class MediaMetadata implements android.os.Parcelable {
method public boolean containsKey(String);
method public int describeContents();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 56610c6a2e09..513e5bb9d084 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -206,6 +206,7 @@ package android.media {
method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpInfo(boolean, int);
method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpSinkInfo(int);
method @NonNull public static android.media.BluetoothProfileConnectionInfo createHearingAidInfo(boolean);
+ method @FlaggedApi("android.media.audio.sco_managed_by_audio") @NonNull public static android.media.BluetoothProfileConnectionInfo createHfpInfo();
method @NonNull public static android.media.BluetoothProfileConnectionInfo createLeAudioInfo(boolean, boolean);
method @NonNull public static android.media.BluetoothProfileConnectionInfo createLeAudioOutputInfo(boolean, int);
method public int describeContents();
diff --git a/core/java/Android.bp b/core/java/Android.bp
index eba500dd32b4..0147910595e1 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -166,6 +166,9 @@ java_library {
"com/android/internal/logging/UiEventLoggerImpl.java",
":statslog-framework-java-gen",
],
+ libs: [
+ "androidx.annotation_annotation",
+ ],
static_libs: ["modules-utils-uieventlogger-interface"],
}
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
index fb06e236dd8a..1265dfa2c441 100644
--- a/core/java/android/accessibilityservice/OWNERS
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -1,6 +1,4 @@
-pweaver@google.com
-ryanlwlin@google.com
-danielnorman@google.com
-sallyyuen@google.com
-aarmaly@google.com
-fuego@google.com
+# Bug component: 44215
+
+# Android Accessibility Framework owners
+include /services/accessibility/OWNERS \ No newline at end of file
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4a9fa9e63bf9..9182716a60cb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -793,7 +793,7 @@ public class Activity extends ContextThemeWrapper
private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
private static final String SAVED_DIALOG_ARGS_KEY_PREFIX = "android:dialog_args_";
- private static final String HAS_CURENT_PERMISSIONS_REQUEST_KEY =
+ private static final String HAS_CURRENT_PERMISSIONS_REQUEST_KEY =
"android:hasCurrentPermissionsRequest";
private static final String REQUEST_PERMISSIONS_WHO_PREFIX = "@android:requestPermissions:";
@@ -9095,14 +9095,14 @@ public class Activity extends ContextThemeWrapper
private void storeHasCurrentPermissionRequest(Bundle bundle) {
if (bundle != null && mHasCurrentPermissionsRequest) {
- bundle.putBoolean(HAS_CURENT_PERMISSIONS_REQUEST_KEY, true);
+ bundle.putBoolean(HAS_CURRENT_PERMISSIONS_REQUEST_KEY, true);
}
}
private void restoreHasCurrentPermissionRequest(Bundle bundle) {
if (bundle != null) {
mHasCurrentPermissionsRequest = bundle.getBoolean(
- HAS_CURENT_PERMISSIONS_REQUEST_KEY, false);
+ HAS_CURRENT_PERMISSIONS_REQUEST_KEY, false);
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6ddb36a72aa9..0e66010ae2c3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4022,6 +4022,13 @@ public final class ActivityThread extends ClientTransactionHandler
ActivityManager.getService().waitForNetworkStateUpdate(mNetworkBlockSeq);
mNetworkBlockSeq = INVALID_PROC_STATE_SEQ;
} catch (RemoteException ignored) {}
+ if (android.app.Flags.clearDnsCacheOnNetworkRulesUpdate()) {
+ // InetAddress will cache UnknownHostException failures. If the rules got
+ // updated and the app has network access now, we need to clear the negative
+ // cache to ensure valid dns queries can work immediately.
+ // TODO: b/329133769 - Clear only the negative cache once it is available.
+ InetAddress.clearDnsCache();
+ }
}
}
}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index ff1ea4f214f6..712f3e534a1c 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -42,6 +42,7 @@ per-file BackgroundStartPrivileges.java = file:/BAL_OWNERS
# ActivityThread
per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
per-file ActivityThread.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ActivityThread.java = file:RESOURCES_OWNERS
# Alarm
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
diff --git a/core/java/android/app/RESOURCES_OWNERS b/core/java/android/app/RESOURCES_OWNERS
index 558280396348..fe37c0ccf5de 100644
--- a/core/java/android/app/RESOURCES_OWNERS
+++ b/core/java/android/app/RESOURCES_OWNERS
@@ -1,3 +1,5 @@
-rtmitchell@google.com
-toddke@google.com
+zyy@google.com
+jakmcbane@google.com
+branliu@google.com
+markpun@google.com
patb@google.com
diff --git a/core/java/android/app/network-policy.aconfig b/core/java/android/app/network-policy.aconfig
new file mode 100644
index 000000000000..88f386f6025d
--- /dev/null
+++ b/core/java/android/app/network-policy.aconfig
@@ -0,0 +1,11 @@
+package: "android.app"
+
+flag {
+ namespace: "backstage_power"
+ name: "clear_dns_cache_on_network_rules_update"
+ description: "Clears the DNS cache when the network rules update"
+ bug: "237556596"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} \ No newline at end of file
diff --git a/core/java/android/content/rollback/OWNERS b/core/java/android/content/rollback/OWNERS
index 8e5a0d8af550..c328b7c36b8f 100644
--- a/core/java/android/content/rollback/OWNERS
+++ b/core/java/android/content/rollback/OWNERS
@@ -1,5 +1,3 @@
# Bug component: 819107
-ancr@google.com
-harshitmahajan@google.com
-robertogil@google.com
+include /services/core/java/com/android/server/crashrecovery/OWNERS \ No newline at end of file
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index db7055b1756d..7f9087baf668 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -1742,7 +1742,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mCallbacks, result.getSequenceId());
}
if ((!mSingleCapture) && (mPreviewProcessorType ==
- IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY)) {
+ IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY)
+ && mInitialized) {
CaptureStageImpl captureStage = null;
try {
captureStage = mPreviewRequestUpdateProcessor.process(
@@ -1765,8 +1766,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} else {
mRequestUpdatedNeeded = false;
}
- } else if (mPreviewProcessorType ==
- IPreviewExtenderImpl.PROCESSOR_TYPE_IMAGE_PROCESSOR) {
+ } else if ((mPreviewProcessorType ==
+ IPreviewExtenderImpl.PROCESSOR_TYPE_IMAGE_PROCESSOR) && mInitialized) {
int idx = mPendingResultMap.indexOfKey(timestamp);
if ((idx >= 0) && (mPendingResultMap.get(timestamp).first == null)) {
@@ -1813,7 +1814,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} else {
// No special handling for PROCESSOR_TYPE_NONE
}
- if (notifyClient) {
+ if (notifyClient && mInitialized) {
final long ident = Binder.clearCallingIdentity();
try {
if (processStatus) {
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 83b7edaec72d..6246dd77fd6d 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -20,10 +20,12 @@ import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
import android.os.Binder;
@@ -69,8 +71,13 @@ import java.util.concurrent.Executor;
* tasks. In Safe Mode, the system will allow underlying cellular networks to be used as default.
* Additionally, during Safe Mode, the VCN will continue to retry the connections, and will
* automatically exit Safe Mode if all active tunnels connect successfully.
+ *
+ * <p>Apps targeting Android 15 or newer should check the existence of {@link
+ * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION} before querying the service. If the feature is
+ * absent, {@link Context#getSystemService} may return null.
*/
@SystemService(Context.VCN_MANAGEMENT_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public class VcnManager {
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index 97b773ee12ec..e64823af84cb 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -20,4 +20,18 @@ flag{
namespace: "vcn"
description: "Feature flag for enabling network metric monitor"
bug: "282996138"
+}
+
+flag{
+ name: "validate_network_on_ipsec_loss"
+ namespace: "vcn"
+ description: "Trigger network validation when IPsec packet loss exceeds the threshold"
+ bug: "329139898"
+}
+
+flag{
+ name: "evaluate_ipsec_loss_on_lp_nc_change"
+ namespace: "vcn"
+ description: "Re-evaluate IPsec packet loss on LinkProperties or NetworkCapabilities change"
+ bug: "323238888"
} \ No newline at end of file
diff --git a/core/java/android/service/media/OWNERS b/core/java/android/service/media/OWNERS
deleted file mode 100644
index 916fc36ffbc6..000000000000
--- a/core/java/android/service/media/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Bug component: 137631
-
-hdmoon@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
-klhyun@google.com
-gyumin@google.com
diff --git a/core/java/android/service/voice/OWNERS b/core/java/android/service/voice/OWNERS
index 763c79e20846..5f9f6bde3129 100644
--- a/core/java/android/service/voice/OWNERS
+++ b/core/java/android/service/voice/OWNERS
@@ -3,5 +3,4 @@
include /core/java/android/app/assist/OWNERS
# The owner here should not be assist owner
-liangyuchen@google.com
adudani@google.com
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index a2f767d002f4..07d05a4ff1ea 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -75,12 +75,14 @@ per-file View.java = file:/graphics/java/android/graphics/OWNERS
per-file View.java = file:/services/core/java/com/android/server/input/OWNERS
per-file View.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file View.java = file:/core/java/android/view/inputmethod/OWNERS
+per-file View.java = file:/core/java/android/text/OWNERS
per-file ViewRootImpl.java = file:/services/accessibility/OWNERS
per-file ViewRootImpl.java = file:/core/java/android/service/autofill/OWNERS
per-file ViewRootImpl.java = file:/graphics/java/android/graphics/OWNERS
per-file ViewRootImpl.java = file:/services/core/java/com/android/server/input/OWNERS
per-file ViewRootImpl.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file ViewRootImpl.java = file:/core/java/android/view/inputmethod/OWNERS
+per-file ViewRootImpl.java = file:/core/java/android/text/OWNERS
per-file AccessibilityInteractionController.java = file:/services/accessibility/OWNERS
per-file OnReceiveContentListener.java = file:/core/java/android/service/autofill/OWNERS
per-file OnReceiveContentListener.java = file:/core/java/android/widget/OWNERS
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 73d134146c3f..b0943e9cff62 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -1,16 +1,13 @@
-# Bug component: 44214
+# Bug component: 44215
-romainguy@google.com
-alanv@google.com
-adamp@google.com
-aurimas@google.com
-nduca@google.com
-sumir@google.com
-ogunwale@google.com
-jjaggi@google.com
-pweaver@google.com
-ryanlwlin@google.com
-danielnorman@google.com
-sallyyuen@google.com
-aarmaly@google.com
-fuego@google.com
+# Android Accessibility Framework owners
+include /services/accessibility/OWNERS
+
+# Android members outside of Accessibility
+adamp@google.com #{LAST_RESORT_SUGGESTION}
+alanv@google.com #{LAST_RESORT_SUGGESTION}
+aurimas@google.com #{LAST_RESORT_SUGGESTION}
+jjaggi@google.com #{LAST_RESORT_SUGGESTION}
+ogunwale@google.com #{LAST_RESORT_SUGGESTION}
+romainguy@google.com #{LAST_RESORT_SUGGESTION}
+sumir@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/core/java/com/android/internal/accessibility/OWNERS b/core/java/com/android/internal/accessibility/OWNERS
index 0955e005791e..1265dfa2c441 100644
--- a/core/java/com/android/internal/accessibility/OWNERS
+++ b/core/java/com/android/internal/accessibility/OWNERS
@@ -1,6 +1,4 @@
-# Bug component: 44214
-pweaver@google.com
-danielnorman@google.com
-sallyyuen@google.com
-aarmaly@google.com
-fuego@google.com
+# Bug component: 44215
+
+# Android Accessibility Framework owners
+include /services/accessibility/OWNERS \ No newline at end of file
diff --git a/core/java/com/android/internal/accessibility/common/MagnificationConstants.java b/core/java/com/android/internal/accessibility/common/MagnificationConstants.java
index 2c493031ea8a..2db3e658530f 100644
--- a/core/java/com/android/internal/accessibility/common/MagnificationConstants.java
+++ b/core/java/com/android/internal/accessibility/common/MagnificationConstants.java
@@ -16,6 +16,8 @@
package com.android.internal.accessibility.common;
+import android.os.SystemProperties;
+
/**
* Collection of common constants for accessibility magnification.
*/
@@ -31,6 +33,7 @@ public final class MagnificationConstants {
/** Minimum supported value for magnification scale. */
public static final float SCALE_MIN_VALUE = 1.0f;
- /** Maximum supported value for magnification scale. */
- public static final float SCALE_MAX_VALUE = 8.0f;
+ /** Maximum supported value for magnification scale. Default of 8.0. */
+ public static final float SCALE_MAX_VALUE =
+ Float.parseFloat(SystemProperties.get("ro.config.max_magnification_scale", "8.0"));
}
diff --git a/core/java/com/android/internal/net/ConnectivityBlobStore.java b/core/java/com/android/internal/net/ConnectivityBlobStore.java
new file mode 100644
index 000000000000..1b18485e35fa
--- /dev/null
+++ b/core/java/com/android/internal/net/ConnectivityBlobStore.java
@@ -0,0 +1,173 @@
+/*
+ * 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 com.android.internal.net;
+
+import android.annotation.NonNull;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Binder;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Database for storing blobs with a key of name strings.
+ * @hide
+ */
+public class ConnectivityBlobStore {
+ private static final String TAG = ConnectivityBlobStore.class.getSimpleName();
+ private static final String TABLENAME = "blob_table";
+ private static final String ROOT_DIR = "/data/misc/connectivityblobdb/";
+
+ private static final String CREATE_TABLE =
+ "CREATE TABLE IF NOT EXISTS " + TABLENAME + " ("
+ + "owner INTEGER,"
+ + "name BLOB,"
+ + "blob BLOB,"
+ + "UNIQUE(owner, name));";
+
+ private final SQLiteDatabase mDb;
+
+ /**
+ * Construct a ConnectivityBlobStore object.
+ *
+ * @param dbName the filename of the database to create/access.
+ */
+ public ConnectivityBlobStore(String dbName) {
+ this(new File(ROOT_DIR + dbName));
+ }
+
+ @VisibleForTesting
+ public ConnectivityBlobStore(File file) {
+ final SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
+ .addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY)
+ .addOpenFlags(SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING)
+ .build();
+ mDb = SQLiteDatabase.openDatabase(file, params);
+ mDb.execSQL(CREATE_TABLE);
+ }
+
+ /**
+ * Stores the blob under the name in the database. Existing blobs by the same name will be
+ * replaced.
+ *
+ * @param name The name of the blob
+ * @param blob The blob.
+ * @return true if the blob was successfully added. False otherwise.
+ * @hide
+ */
+ public boolean put(@NonNull String name, @NonNull byte[] blob) {
+ final int ownerUid = Binder.getCallingUid();
+ final ContentValues values = new ContentValues();
+ values.put("owner", ownerUid);
+ values.put("name", name);
+ values.put("blob", blob);
+
+ // No need for try-catch since it is done within db.replace
+ // nullColumnHack is for the case where values may be empty since SQL does not allow
+ // inserting a completely empty row. Since values is never empty, set this to null.
+ final long res = mDb.replace(TABLENAME, null /* nullColumnHack */, values);
+ return res > 0;
+ }
+
+ /**
+ * Retrieves a blob by the name from the database.
+ *
+ * @param name Name of the blob to retrieve.
+ * @return The unstructured blob, that is the blob that was stored using
+ * {@link com.android.internal.net.ConnectivityBlobStore#put}.
+ * Returns null if no blob was found.
+ * @hide
+ */
+ public byte[] get(@NonNull String name) {
+ final int ownerUid = Binder.getCallingUid();
+ try (Cursor cursor = mDb.query(TABLENAME,
+ new String[] {"blob"} /* columns */,
+ "owner=? AND name=?" /* selection */,
+ new String[] {Integer.toString(ownerUid), name} /* selectionArgs */,
+ null /* groupBy */,
+ null /* having */,
+ null /* orderBy */)) {
+ if (cursor.moveToFirst()) {
+ return cursor.getBlob(0);
+ }
+ } catch (SQLException e) {
+ Log.e(TAG, "Error in getting " + name + ": " + e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Removes a blob by the name from the database.
+ *
+ * @param name Name of the blob to be removed.
+ * @return True if a blob was removed. False if no such name was found.
+ * @hide
+ */
+ public boolean remove(@NonNull String name) {
+ final int ownerUid = Binder.getCallingUid();
+ try {
+ final int res = mDb.delete(TABLENAME,
+ "owner=? AND name=?" /* whereClause */,
+ new String[] {Integer.toString(ownerUid), name} /* whereArgs */);
+ return res > 0;
+ } catch (SQLException e) {
+ Log.e(TAG, "Error in removing " + name + ": " + e);
+ return false;
+ }
+ }
+
+ /**
+ * Lists the name suffixes stored in the database matching the given prefix, sorted in
+ * ascending order.
+ *
+ * @param prefix String of prefix to list from the stored names.
+ * @return An array of strings representing the name suffixes stored in the database
+ * matching the given prefix, sorted in ascending order.
+ * The return value may be empty but never null.
+ * @hide
+ */
+ public String[] list(@NonNull String prefix) {
+ final int ownerUid = Binder.getCallingUid();
+ final List<String> names = new ArrayList<String>();
+ try (Cursor cursor = mDb.query(TABLENAME,
+ new String[] {"name"} /* columns */,
+ "owner=? AND name LIKE ?" /* selection */,
+ new String[] {Integer.toString(ownerUid), prefix + "%"} /* selectionArgs */,
+ null /* groupBy */,
+ null /* having */,
+ "name ASC" /* orderBy */)) {
+ if (cursor.moveToFirst()) {
+ do {
+ final String name = cursor.getString(0);
+ names.add(name.substring(prefix.length()));
+ } while (cursor.moveToNext());
+ }
+ } catch (SQLException e) {
+ Log.e(TAG, "Error in listing " + prefix + ": " + e);
+ }
+
+ return names.toArray(new String[names.size()]);
+ }
+}
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 3aca751edb0d..d687ef375bc3 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -1,6 +1,5 @@
# Camera
-per-file *Camera*,*camera* = cychen@google.com, epeev@google.com, etalvala@google.com
-per-file *Camera*,*camera* = shuzhenwang@google.com, yinchiayeh@google.com, zhijunhe@google.com
+per-file *Camera*,*camera* = file:platform/frameworks/av:/camera/OWNERS
# Connectivity
per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f40d6c455e1a..7bac3381193d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -154,6 +154,7 @@
<protected-broadcast android:name="android.app.backup.intent.INIT" />
<protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" />
+ <protected-broadcast android:name="android.bluetooth.action.AUTO_ON_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 7d740ef76daf..c8625b9114da 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -42,8 +42,8 @@
<!-- Argentina: 5 digits, known short codes listed -->
<shortcode country="ar" pattern="\\d{5}" free="11711|28291|44077|78887" />
- <!-- Armenia: 3-4 digits, emergency numbers 10[123] -->
- <shortcode country="am" pattern="\\d{3,4}" premium="11[2456]1|3024" free="10[123]" />
+ <!-- Armenia: 3-5 digits, emergency numbers 10[123] -->
+ <shortcode country="am" pattern="\\d{3,5}" premium="11[2456]1|3024" free="10[123]|71522|71512|71502" />
<!-- Austria: 10 digits, premium prefix 09xx, plus EU -->
<shortcode country="at" pattern="11\\d{4}" premium="09.*" free="116\\d{3}" />
@@ -111,7 +111,7 @@
<shortcode country="do" pattern="\\d{1,6}" free="912892" />
<!-- Ecuador: 1-6 digits (standard system default, not country specific) -->
- <shortcode country="ec" pattern="\\d{1,6}" free="466453" />
+ <shortcode country="ec" pattern="\\d{1,6}" free="466453|18512" />
<!-- Estonia: short codes 3-5 digits starting with 1, plus premium 7 digit numbers starting with 90, plus EU.
http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht -->
@@ -137,11 +137,11 @@
visual voicemail code for EE: 887 -->
<shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726|88555|9017|9018" />
- <!-- Georgia: 4 digits, known premium codes listed -->
- <shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
+ <!-- Georgia: 1-5 digits, known premium codes listed -->
+ <shortcode country="ge" pattern="\\d{1,5}" premium="801[234]|888[239]" free="95201|95202|95203" />
<!-- Ghana: 4 digits, known premium codes listed -->
- <shortcode country="gh" pattern="\\d{4}" free="5041" />
+ <shortcode country="gh" pattern="\\d{4}" free="5041|3777" />
<!-- Greece: 5 digits (54xxx, 19yxx, x=0-9, y=0-5): http://www.cmtelecom.com/premium-sms/greece -->
<shortcode country="gr" pattern="\\d{5}" premium="54\\d{3}|19[0-5]\\d{2}" free="116\\d{3}|12115" />
@@ -210,6 +210,9 @@
<!-- Macedonia: 1-6 digits (not confirmed), known premium codes listed -->
<shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
+ <!-- Mongolia : 1-6 digits (standard system default, not country specific) -->
+ <shortcode country="mn" pattern="\\d{1,6}" free="44444|45678|445566" />
+
<!-- Malawi: 1-5 digits (standard system default, not country specific) -->
<shortcode country="mw" pattern="\\d{1,5}" free="4276" />
@@ -247,7 +250,7 @@
<shortcode country="ph" pattern="\\d{1,5}" free="2147|5495|5496" />
<!-- Pakistan -->
- <shortcode country="pk" pattern="\\d{1,5}" free="2057|9092" />
+ <shortcode country="pk" pattern="\\d{1,6}" free="2057|9092|909203" />
<!-- Palestine: 5 digits, known premium codes listed -->
<shortcode country="ps" pattern="\\d{1,5}" free="37477|6681" />
@@ -291,7 +294,7 @@
<shortcode country="sk" premium="\\d{4}" free="116\\d{3}|8000" />
<!-- Senegal(SN): 1-5 digits (standard system default, not country specific) -->
- <shortcode country="sn" pattern="\\d{1,5}" free="21215" />
+ <shortcode country="sn" pattern="\\d{1,5}" free="21215|21098" />
<!-- El Salvador(SV): 1-5 digits (standard system default, not country specific) -->
<shortcode country="sv" pattern="\\d{4,6}" free="466453" />
@@ -321,14 +324,17 @@
visual voicemail code for T-Mobile: 122 -->
<shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611|96831" />
+ <!--Uruguay : 1-5 digits (standard system default, not country specific) -->
+ <shortcode country="uy" pattern="\\d{1,5}" free="55002" />
+
<!-- Vietnam: 1-5 digits (standard system default, not country specific) -->
- <shortcode country="vn" pattern="\\d{1,5}" free="5001|9055" />
+ <shortcode country="vn" pattern="\\d{1,5}" free="5001|9055|8079" />
<!-- Mayotte (French Territory): 1-5 digits (not confirmed) -->
<shortcode country="yt" pattern="\\d{1,5}" free="38600,36300,36303,959" />
<!-- South Africa -->
- <shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056" />
+ <shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056|33009" />
<!-- Zimbabwe -->
<shortcode country="zw" pattern="\\d{1,5}" free="33679" />
diff --git a/core/tests/bugreports/OWNERS b/core/tests/bugreports/OWNERS
new file mode 100644
index 000000000000..dbd767c78853
--- /dev/null
+++ b/core/tests/bugreports/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 153446
+file:/platform/frameworks/native:/cmds/dumpstate/OWNERS
diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
index de7244d49834..71c068d7ad46 100644
--- a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
@@ -149,7 +149,7 @@ public class DateIntervalFormatTest {
FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19.–22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19.01. – 22.04.2009",
+ assertEquals("19.01.\u2009–\u200922.04.2009",
formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19.01.2009\u2009\u2013\u200909.02.2012",
@@ -220,10 +220,10 @@ public class DateIntervalFormatTest {
formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0));
assertEquals("19.–22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("Mo., 19. – Do., 22. Jan. 2009",
+ assertEquals("Mo., 19.\u2009–\u2009Do., 22. Jan. 2009",
formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("Montag, 19. – Donnerstag, 22. Januar 2009",
+ assertEquals("Montag, 19.\u2009–\u2009Donnerstag, 22. Januar 2009",
formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
assertEquals("19. Januar\u2009\u2013\u200922. April 2009",
diff --git a/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java b/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java
new file mode 100644
index 000000000000..68545cfe889c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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 com.android.internal.net;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConnectivityBlobStoreTest {
+ private static final String DATABASE_FILENAME = "ConnectivityBlobStore.db";
+ private static final String TEST_NAME = "TEST_NAME";
+ private static final byte[] TEST_BLOB = new byte[] {(byte) 10, (byte) 90, (byte) 45, (byte) 12};
+
+ private Context mContext;
+ private File mFile;
+
+ private ConnectivityBlobStore createConnectivityBlobStore() {
+ return new ConnectivityBlobStore(mFile);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mFile = mContext.getDatabasePath(DATABASE_FILENAME);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mContext.deleteDatabase(DATABASE_FILENAME);
+ }
+
+ @Test
+ public void testFileCreateDelete() {
+ assertFalse(mFile.exists());
+ createConnectivityBlobStore();
+ assertTrue(mFile.exists());
+
+ assertTrue(mContext.deleteDatabase(DATABASE_FILENAME));
+ assertFalse(mFile.exists());
+ }
+
+ @Test
+ public void testPutAndGet() throws Exception {
+ final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+ assertNull(connectivityBlobStore.get(TEST_NAME));
+
+ assertTrue(connectivityBlobStore.put(TEST_NAME, TEST_BLOB));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(TEST_NAME));
+
+ // Test replacement
+ final byte[] newBlob = new byte[] {(byte) 15, (byte) 20};
+ assertTrue(connectivityBlobStore.put(TEST_NAME, newBlob));
+ assertArrayEquals(newBlob, connectivityBlobStore.get(TEST_NAME));
+ }
+
+ @Test
+ public void testRemove() throws Exception {
+ final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+ assertNull(connectivityBlobStore.get(TEST_NAME));
+ assertFalse(connectivityBlobStore.remove(TEST_NAME));
+
+ assertTrue(connectivityBlobStore.put(TEST_NAME, TEST_BLOB));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(TEST_NAME));
+
+ assertTrue(connectivityBlobStore.remove(TEST_NAME));
+ assertNull(connectivityBlobStore.get(TEST_NAME));
+
+ // Removing again returns false
+ assertFalse(connectivityBlobStore.remove(TEST_NAME));
+ }
+
+ @Test
+ public void testMultipleNames() throws Exception {
+ final String name1 = TEST_NAME + "1";
+ final String name2 = TEST_NAME + "2";
+ final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+
+ assertNull(connectivityBlobStore.get(name1));
+ assertNull(connectivityBlobStore.get(name2));
+ assertFalse(connectivityBlobStore.remove(name1));
+ assertFalse(connectivityBlobStore.remove(name2));
+
+ assertTrue(connectivityBlobStore.put(name1, TEST_BLOB));
+ assertTrue(connectivityBlobStore.put(name2, TEST_BLOB));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(name1));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(name2));
+
+ // Replace the blob for name1 only.
+ final byte[] newBlob = new byte[] {(byte) 16, (byte) 21};
+ assertTrue(connectivityBlobStore.put(name1, newBlob));
+ assertArrayEquals(newBlob, connectivityBlobStore.get(name1));
+
+ assertTrue(connectivityBlobStore.remove(name1));
+ assertNull(connectivityBlobStore.get(name1));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(name2));
+
+ assertFalse(connectivityBlobStore.remove(name1));
+ assertTrue(connectivityBlobStore.remove(name2));
+ assertNull(connectivityBlobStore.get(name2));
+ assertFalse(connectivityBlobStore.remove(name2));
+ }
+
+ @Test
+ public void testList() throws Exception {
+ final String[] unsortedNames = new String[] {
+ TEST_NAME + "1",
+ TEST_NAME + "2",
+ TEST_NAME + "0",
+ "NON_MATCHING_PREFIX",
+ "MATCHING_SUFFIX_" + TEST_NAME
+ };
+ // Expected to match and discard the prefix and be in increasing sorted order.
+ final String[] expected = new String[] {
+ "0",
+ "1",
+ "2"
+ };
+ final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+
+ for (int i = 0; i < unsortedNames.length; i++) {
+ assertTrue(connectivityBlobStore.put(unsortedNames[i], TEST_BLOB));
+ }
+ final String[] actual = connectivityBlobStore.list(TEST_NAME /* prefix */);
+ assertArrayEquals(expected, actual);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/net/OWNERS b/core/tests/coretests/src/com/android/internal/net/OWNERS
new file mode 100644
index 000000000000..f51ba475ab63
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/net/OWNERS
@@ -0,0 +1 @@
+include /core/java/com/android/internal/net/OWNERS
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 245f21658b7a..701d145fe805 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -12,3 +12,4 @@ yamasani@google.com
per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
per-file services.core.protolog.json = file:/services/core/java/com/android/server/wm/OWNERS
+per-file core.protolog.pb = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 9320c144d2ec..d1aa8e9734c2 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -1432,6 +1432,16 @@
postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
</font>
</family>
+ <family lang="ja">
+ <font weight="400" style="normal" postScriptName="NotoSerifHentaigana-ExtraLight">
+ NotoSerifHentaigana.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSerifHentaigana-ExtraLight">
+ NotoSerifHentaigana.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
<family lang="ko">
<font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
NotoSansCJK-Regular.ttc
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 2430e8d8e662..efbbfc23736f 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -175,20 +175,6 @@ public class AndroidKeyStoreMaintenance {
}
/**
- * Informs Keystore 2.0 that an off body event was detected.
- */
- public static void onDeviceOffBody() {
- StrictMode.noteDiskWrite();
- try {
- getService().onDeviceOffBody();
- } catch (Exception e) {
- // TODO This fails open. This is not a regression with respect to keystore1 but it
- // should get fixed.
- Log.e(TAG, "Error while reporting device off body event.", e);
- }
- }
-
- /**
* Migrates a key given by the source descriptor to the location designated by the destination
* descriptor.
*
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index bd9abec22325..2cac2e150919 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -17,7 +17,6 @@
package android.security;
import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
import android.os.StrictMode;
/**
@@ -30,10 +29,6 @@ import android.os.StrictMode;
*/
public class KeyStore {
- // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int NO_ERROR = 1;
-
// Used for UID field to indicate the calling UID.
public static final int UID_SELF = -1;
@@ -48,19 +43,12 @@ public class KeyStore {
* Add an authentication record to the keystore authorization table.
*
* @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
- * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
- * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
+ * @return 0 on success, otherwise an error value corresponding to a
+ * {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
*/
public int addAuthToken(byte[] authToken) {
StrictMode.noteDiskWrite();
return Authorization.addAuthToken(authToken);
}
-
- /**
- * Notify keystore that the device went off-body.
- */
- public void onDeviceOffBody() {
- AndroidKeyStoreMaintenance.onDeviceOffBody();
- }
}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 7aecfd8d4a0d..d359a9050a0f 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -880,9 +880,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
}
/**
- * Returns {@code true} if the screen must be unlocked for this key to be used for decryption or
- * signing. Encryption and signature verification will still be available when the screen is
- * locked.
+ * Returns {@code true} if the key is authorized to be used only while the device is unlocked.
*
* @see Builder#setUnlockedDeviceRequired(boolean)
*/
@@ -1672,16 +1670,16 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
* {@link #setUserAuthenticationValidityDurationSeconds} and
* {@link #setUserAuthenticationRequired}). Once the device has been removed from the
* user's body, the key will be considered unauthorized and the user will need to
- * re-authenticate to use it. For keys without an authentication validity period this
- * parameter has no effect.
- *
- * <p>Similarly, on devices that do not have an on-body sensor, this parameter will have no
- * effect; the device will always be considered to be "on-body" and the key will therefore
- * remain authorized until the validity period ends.
- *
- * @param remainsValid if {@code true}, and if the device supports on-body detection, key
- * will be invalidated when the device is removed from the user's body or when the
- * authentication validity expires, whichever occurs first.
+ * re-authenticate to use it. If the device does not have an on-body sensor or the key does
+ * not have an authentication validity period, this parameter has no effect.
+ * <p>
+ * Since Android 12 (API level 31), this parameter has no effect even on devices that have
+ * an on-body sensor. A future version of Android may restore enforcement of this parameter.
+ * Meanwhile, it is recommended to not use it.
+ *
+ * @param remainsValid if {@code true}, and if the device supports enforcement of this
+ * parameter, the key will be invalidated when the device is removed from the user's body or
+ * when the authentication validity expires, whichever occurs first.
*/
@NonNull
public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) {
@@ -1723,11 +1721,49 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
}
/**
- * Sets whether the keystore requires the screen to be unlocked before allowing decryption
- * using this key. If this is set to {@code true}, any attempt to decrypt or sign using this
- * key while the screen is locked will fail. A locked device requires a PIN, password,
- * biometric, or other trusted factor to access. While the screen is locked, any associated
- * public key can still be used (e.g for signature verification).
+ * Sets whether this key is authorized to be used only while the device is unlocked.
+ * <p>
+ * The device is considered to be locked for a user when the user's apps are currently
+ * inaccessible and some form of lock screen authentication is required to regain access to
+ * them. For the full definition, see {@link KeyguardManager#isDeviceLocked()}.
+ * <p>
+ * Public key operations aren't restricted by {@code setUnlockedDeviceRequired(true)} and
+ * may be performed even while the device is locked. In Android 11 (API level 30) and lower,
+ * encryption and verification operations with symmetric keys weren't restricted either.
+ * <p>
+ * Keys that use {@code setUnlockedDeviceRequired(true)} can be imported and generated even
+ * while the device is locked, as long as the device has been unlocked at least once since
+ * the last reboot. However, such keys cannot be used (except for the unrestricted
+ * operations mentioned above) until the device is unlocked. Apps that need to encrypt data
+ * while the device is locked such that it can only be decrypted while the device is
+ * unlocked can generate a key and encrypt the data in software, import the key into
+ * Keystore using {@code setUnlockedDeviceRequired(true)}, and zeroize the original key.
+ * <p>
+ * {@code setUnlockedDeviceRequired(true)} is related to but distinct from
+ * {@link #setUserAuthenticationRequired(boolean) setUserAuthenticationRequired(true)}.
+ * {@code setUnlockedDeviceRequired(true)} requires that the device be unlocked, whereas
+ * {@code setUserAuthenticationRequired(true)} requires that a specific type of strong
+ * authentication has happened within a specific time period. They may be used together or
+ * separately; there are cases in which one requirement can be satisfied but not the other.
+ * <p>
+ * <b>Warning:</b> Be careful using {@code setUnlockedDeviceRequired(true)} on Android 14
+ * (API level 34) and lower, since the following bugs existed in Android 12 through 14:
+ * <ul>
+ * <li>When the user didn't have a secure lock screen, unlocked-device-required keys
+ * couldn't be generated, imported, or used.</li>
+ * <li>When the user's secure lock screen was removed, all of that user's
+ * unlocked-device-required keys were automatically deleted.</li>
+ * <li>Unlocking the device with a non-strong biometric, such as face on many devices,
+ * didn't re-authorize the use of unlocked-device-required keys.</li>
+ * <li>Unlocking the device with a biometric didn't re-authorize the use of
+ * unlocked-device-required keys in profiles that share their parent user's lock.</li>
+ * </ul>
+ * These issues are fixed in Android 15, so apps can avoid them by using
+ * {@code setUnlockedDeviceRequired(true)} only on Android 15 and higher.
+ * Apps that use both {@code setUnlockedDeviceRequired(true)} and
+ * {@link #setUserAuthenticationRequired(boolean) setUserAuthenticationRequired(true)}
+ * are unaffected by the first two issues, since the first two issues describe expected
+ * behavior for {@code setUserAuthenticationRequired(true)}.
*/
@NonNull
public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index 5cffe46936a2..2163ca2f8217 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -279,7 +279,7 @@ public class KeyInfo implements KeySpec {
}
/**
- * Returns {@code true} if the key is authorized to be used only when the device is unlocked.
+ * Returns {@code true} if the key is authorized to be used only while the device is unlocked.
*
* <p>This authorization applies only to secret key and private key operations. Public key
* operations are not restricted.
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 31b4a5eac619..8e5ac45d394d 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -577,9 +577,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
}
/**
- * Returns {@code true} if the screen must be unlocked for this key to be used for decryption or
- * signing. Encryption and signature verification will still be available when the screen is
- * locked.
+ * Returns {@code true} if the key is authorized to be used only while the device is unlocked.
*
* @see Builder#setUnlockedDeviceRequired(boolean)
*/
@@ -1039,16 +1037,16 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
* {@link #setUserAuthenticationValidityDurationSeconds} and
* {@link #setUserAuthenticationRequired}). Once the device has been removed from the
* user's body, the key will be considered unauthorized and the user will need to
- * re-authenticate to use it. For keys without an authentication validity period this
- * parameter has no effect.
+ * re-authenticate to use it. If the device does not have an on-body sensor or the key does
+ * not have an authentication validity period, this parameter has no effect.
+ * <p>
+ * Since Android 12 (API level 31), this parameter has no effect even on devices that have
+ * an on-body sensor. A future version of Android may restore enforcement of this parameter.
+ * Meanwhile, it is recommended to not use it.
*
- * <p>Similarly, on devices that do not have an on-body sensor, this parameter will have no
- * effect; the device will always be considered to be "on-body" and the key will therefore
- * remain authorized until the validity period ends.
- *
- * @param remainsValid if {@code true}, and if the device supports on-body detection, key
- * will be invalidated when the device is removed from the user's body or when the
- * authentication validity expires, whichever occurs first.
+ * @param remainsValid if {@code true}, and if the device supports enforcement of this
+ * parameter, the key will be invalidated when the device is removed from the user's body or
+ * when the authentication validity expires, whichever occurs first.
*/
@NonNull
public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) {
@@ -1117,11 +1115,49 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
}
/**
- * Sets whether the keystore requires the screen to be unlocked before allowing decryption
- * using this key. If this is set to {@code true}, any attempt to decrypt or sign using this
- * key while the screen is locked will fail. A locked device requires a PIN, password,
- * biometric, or other trusted factor to access. While the screen is locked, the key can
- * still be used for encryption or signature verification.
+ * Sets whether this key is authorized to be used only while the device is unlocked.
+ * <p>
+ * The device is considered to be locked for a user when the user's apps are currently
+ * inaccessible and some form of lock screen authentication is required to regain access to
+ * them. For the full definition, see {@link KeyguardManager#isDeviceLocked()}.
+ * <p>
+ * Public key operations aren't restricted by {@code setUnlockedDeviceRequired(true)} and
+ * may be performed even while the device is locked. In Android 11 (API level 30) and lower,
+ * encryption and verification operations with symmetric keys weren't restricted either.
+ * <p>
+ * Keys that use {@code setUnlockedDeviceRequired(true)} can be imported and generated even
+ * while the device is locked, as long as the device has been unlocked at least once since
+ * the last reboot. However, such keys cannot be used (except for the unrestricted
+ * operations mentioned above) until the device is unlocked. Apps that need to encrypt data
+ * while the device is locked such that it can only be decrypted while the device is
+ * unlocked can generate a key and encrypt the data in software, import the key into
+ * Keystore using {@code setUnlockedDeviceRequired(true)}, and zeroize the original key.
+ * <p>
+ * {@code setUnlockedDeviceRequired(true)} is related to but distinct from
+ * {@link #setUserAuthenticationRequired(boolean) setUserAuthenticationRequired(true)}.
+ * {@code setUnlockedDeviceRequired(true)} requires that the device be unlocked, whereas
+ * {@code setUserAuthenticationRequired(true)} requires that a specific type of strong
+ * authentication has happened within a specific time period. They may be used together or
+ * separately; there are cases in which one requirement can be satisfied but not the other.
+ * <p>
+ * <b>Warning:</b> Be careful using {@code setUnlockedDeviceRequired(true)} on Android 14
+ * (API level 34) and lower, since the following bugs existed in Android 12 through 14:
+ * <ul>
+ * <li>When the user didn't have a secure lock screen, unlocked-device-required keys
+ * couldn't be generated, imported, or used.</li>
+ * <li>When the user's secure lock screen was removed, all of that user's
+ * unlocked-device-required keys were automatically deleted.</li>
+ * <li>Unlocking the device with a non-strong biometric, such as face on many devices,
+ * didn't re-authorize the use of unlocked-device-required keys.</li>
+ * <li>Unlocking the device with a biometric didn't re-authorize the use of
+ * unlocked-device-required keys in profiles that share their parent user's lock.</li>
+ * </ul>
+ * These issues are fixed in Android 15, so apps can avoid them by using
+ * {@code setUnlockedDeviceRequired(true)} only on Android 15 and higher.
+ * Apps that use both {@code setUnlockedDeviceRequired(true)} and
+ * {@link #setUserAuthenticationRequired(boolean) setUserAuthenticationRequired(true)}
+ * are unaffected by the first two issues, since the first two issues describe expected
+ * behavior for {@code setUserAuthenticationRequired(true)}.
*/
@NonNull
public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index 101a10e3d312..3f39eeb0cc6b 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -359,14 +359,12 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
} catch (KeyStoreException keyStoreException) {
GeneralSecurityException e = KeyStoreCryptoOperationUtils.getExceptionForCipherInit(
mKey, keyStoreException);
- if (e != null) {
- if (e instanceof InvalidKeyException) {
- throw (InvalidKeyException) e;
- } else if (e instanceof InvalidAlgorithmParameterException) {
- throw (InvalidAlgorithmParameterException) e;
- } else {
- throw new ProviderException("Unexpected exception type", e);
- }
+ if (e instanceof InvalidKeyException) {
+ throw (InvalidKeyException) e;
+ } else if (e instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException) e;
+ } else {
+ throw new ProviderException("Unexpected exception type", e);
}
}
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
index 372e4cb3d72e..9b82206e5709 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
@@ -20,7 +20,6 @@ import android.app.ActivityThread;
import android.hardware.biometrics.BiometricManager;
import android.hardware.security.keymint.ErrorCode;
import android.security.GateKeeper;
-import android.security.KeyStore;
import android.security.KeyStoreException;
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
@@ -131,15 +130,10 @@ abstract class KeyStoreCryptoOperationUtils {
/**
* Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
- * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
- * should succeed.
+ * in response to a failed {code IKeystoreSecurityLevel#createOperation()}.
*/
public static GeneralSecurityException getExceptionForCipherInit(
AndroidKeyStoreKey key, KeyStoreException e) {
- if (e.getErrorCode() == KeyStore.NO_ERROR) {
- return null;
- }
-
// Cipher-specific cases
switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_INVALID_NONCE:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 96e57e71f05c..99b18d7d860d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -29,6 +29,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -2671,7 +2672,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
+ " with " + taskInfo.taskId + " before startAnimation().");
record.addRecord(stage, true, taskInfo.taskId);
}
- } else if (isClosingType(change.getMode())) {
+ } else if (change.getMode() == TRANSIT_CLOSE) {
if (stage.containsTask(taskInfo.taskId)) {
record.addRecord(stage, false, taskInfo.taskId);
Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called"
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index 6ccb212fe6ca..40dfc9d4309b 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -16,6 +16,7 @@
#pragma once
+#include <FileBlobCache.h>
#include <GrContextOptions.h>
#include <SkRefCnt.h>
#include <cutils/compiler.h>
@@ -32,7 +33,6 @@ class SkData;
namespace android {
class BlobCache;
-class FileBlobCache;
namespace uirenderer {
namespace skiapipeline {
diff --git a/media/OWNERS b/media/OWNERS
index 994a7b810009..1e5a458a5bff 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -3,14 +3,10 @@ atneya@google.com
elaurent@google.com
essick@google.com
etalvala@google.com
-hdmoon@google.com
hunga@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
+jchowdhary@google.com
jmtrivi@google.com
jsharkey@android.com
-klhyun@google.com
lajos@google.com
nchalko@google.com
philburk@google.com
@@ -20,8 +16,6 @@ wonsik@google.com
# go/android-fwk-media-solutions for info on areas of ownership.
include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
-# SEO
-
# SEA/KIR/BVE
jtinker@google.com
robertshih@google.com
diff --git a/media/java/android/media/AudioDescriptor.java b/media/java/android/media/AudioDescriptor.java
index 85a653c9d80c..b5cae2c5ef10 100644
--- a/media/java/android/media/AudioDescriptor.java
+++ b/media/java/android/media/AudioDescriptor.java
@@ -99,7 +99,7 @@ public class AudioDescriptor implements Parcelable {
* When encapsulation is required, only playback with {@link android.media.AudioTrack} API is
* supported. But playback with {@link android.media.MediaPlayer} is not.
* When an encapsulation type is required, the {@link AudioFormat} encoding selected when
- * creating the {@link AudioTrack} must match the encapsulation type, e.g
+ * creating the {@link AudioTrack} must match the encapsulation type, e.g.
* AudioFormat#ENCODING_IEC61937 for AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937.
*
* @return an integer representing the encapsulation type
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3dfd5726455d..cff5f20669d2 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3460,7 +3460,7 @@ public class AudioManager {
/* modes for setMode/getMode/setRoute/getRoute */
/**
- * Audio harware modes.
+ * Audio hardware modes.
*/
/**
* Invalid audio mode.
diff --git a/media/java/android/media/BluetoothProfileConnectionInfo.java b/media/java/android/media/BluetoothProfileConnectionInfo.java
index e4dc1521ae70..0613fc655521 100644
--- a/media/java/android/media/BluetoothProfileConnectionInfo.java
+++ b/media/java/android/media/BluetoothProfileConnectionInfo.java
@@ -15,6 +15,9 @@
*/
package android.media;
+import static android.media.audio.Flags.FLAG_SCO_MANAGED_BY_AUDIO;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.bluetooth.BluetoothProfile;
@@ -174,4 +177,13 @@ public final class BluetoothProfileConnectionInfo implements Parcelable {
public boolean isLeOutput() {
return mIsLeOutput;
}
+
+ /**
+ * Factory method for <code>BluetoothProfileConnectionInfo</code> for an HFP device.
+ */
+ @FlaggedApi(FLAG_SCO_MANAGED_BY_AUDIO)
+ public static @NonNull BluetoothProfileConnectionInfo createHfpInfo() {
+ return new BluetoothProfileConnectionInfo(BluetoothProfile.HEADSET, false,
+ -1, false);
+ }
}
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index ab7c27f70e05..2d7db5e6ed94 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -35,6 +35,7 @@ import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.IHwBinder;
import android.os.Looper;
import android.os.Message;
@@ -43,7 +44,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.util.Log;
-import android.util.Singleton;
import com.android.internal.util.FrameworkStatsLog;
@@ -264,71 +264,107 @@ public final class MediaCas implements AutoCloseable {
public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED =
android.hardware.cas.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
- private static final Singleton<IMediaCasService> sService =
- new Singleton<IMediaCasService>() {
+ private static IMediaCasService sService = null;
+ private static Object sAidlLock = new Object();
+
+ /** DeathListener for AIDL service */
+ private static IBinder.DeathRecipient sDeathListener =
+ new IBinder.DeathRecipient() {
@Override
- protected IMediaCasService create() {
- try {
- Log.d(TAG, "Trying to get AIDL service");
- IMediaCasService serviceAidl =
- IMediaCasService.Stub.asInterface(
- ServiceManager.waitForDeclaredService(
- IMediaCasService.DESCRIPTOR + "/default"));
- if (serviceAidl != null) {
- return serviceAidl;
- }
- } catch (Exception eAidl) {
- Log.d(TAG, "Failed to get cas AIDL service");
+ public void binderDied() {
+ synchronized (sAidlLock) {
+ Log.d(TAG, "The service is dead");
+ sService.asBinder().unlinkToDeath(sDeathListener, 0);
+ sService = null;
}
- return null;
}
};
- private static final Singleton<android.hardware.cas.V1_0.IMediaCasService> sServiceHidl =
- new Singleton<android.hardware.cas.V1_0.IMediaCasService>() {
- @Override
- protected android.hardware.cas.V1_0.IMediaCasService create() {
- try {
- Log.d(TAG, "Trying to get cas@1.2 service");
- android.hardware.cas.V1_2.IMediaCasService serviceV12 =
- android.hardware.cas.V1_2.IMediaCasService.getService(
- true /*wait*/);
- if (serviceV12 != null) {
- return serviceV12;
- }
- } catch (Exception eV1_2) {
- Log.d(TAG, "Failed to get cas@1.2 service");
+ static IMediaCasService getService() {
+ synchronized (sAidlLock) {
+ if (sService == null || !sService.asBinder().isBinderAlive()) {
+ try {
+ Log.d(TAG, "Trying to get AIDL service");
+ sService =
+ IMediaCasService.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(
+ IMediaCasService.DESCRIPTOR + "/default"));
+ if (sService != null) {
+ sService.asBinder().linkToDeath(sDeathListener, 0);
}
+ } catch (Exception eAidl) {
+ Log.d(TAG, "Failed to get cas AIDL service");
+ }
+ }
+ return sService;
+ }
+ }
- try {
- Log.d(TAG, "Trying to get cas@1.1 service");
- android.hardware.cas.V1_1.IMediaCasService serviceV11 =
- android.hardware.cas.V1_1.IMediaCasService.getService(
- true /*wait*/);
- if (serviceV11 != null) {
- return serviceV11;
+ private static android.hardware.cas.V1_0.IMediaCasService sServiceHidl = null;
+ private static Object sHidlLock = new Object();
+
+ /** Used to indicate the right end-point to handle the serviceDied method */
+ private static final long MEDIA_CAS_HIDL_COOKIE = 394;
+
+ /** DeathListener for HIDL service */
+ private static IHwBinder.DeathRecipient sDeathListenerHidl =
+ new IHwBinder.DeathRecipient() {
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == MEDIA_CAS_HIDL_COOKIE) {
+ synchronized (sHidlLock) {
+ sServiceHidl = null;
}
- } catch (Exception eV1_1) {
- Log.d(TAG, "Failed to get cas@1.1 service");
}
+ }
+ };
- try {
- Log.d(TAG, "Trying to get cas@1.0 service");
- return android.hardware.cas.V1_0.IMediaCasService.getService(true /*wait*/);
- } catch (Exception eV1_0) {
- Log.d(TAG, "Failed to get cas@1.0 service");
+ static android.hardware.cas.V1_0.IMediaCasService getServiceHidl() {
+ synchronized (sHidlLock) {
+ if (sServiceHidl != null) {
+ return sServiceHidl;
+ } else {
+ try {
+ Log.d(TAG, "Trying to get cas@1.2 service");
+ android.hardware.cas.V1_2.IMediaCasService serviceV12 =
+ android.hardware.cas.V1_2.IMediaCasService.getService(true /*wait*/);
+ if (serviceV12 != null) {
+ sServiceHidl = serviceV12;
+ sServiceHidl.linkToDeath(sDeathListenerHidl, MEDIA_CAS_HIDL_COOKIE);
+ return sServiceHidl;
}
-
- return null;
+ } catch (Exception eV1_2) {
+ Log.d(TAG, "Failed to get cas@1.2 service");
}
- };
- static IMediaCasService getService() {
- return sService.get();
- }
+ try {
+ Log.d(TAG, "Trying to get cas@1.1 service");
+ android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+ android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
+ if (serviceV11 != null) {
+ sServiceHidl = serviceV11;
+ sServiceHidl.linkToDeath(sDeathListenerHidl, MEDIA_CAS_HIDL_COOKIE);
+ return sServiceHidl;
+ }
+ } catch (Exception eV1_1) {
+ Log.d(TAG, "Failed to get cas@1.1 service");
+ }
- static android.hardware.cas.V1_0.IMediaCasService getServiceHidl() {
- return sServiceHidl.get();
+ try {
+ Log.d(TAG, "Trying to get cas@1.0 service");
+ sServiceHidl =
+ android.hardware.cas.V1_0.IMediaCasService.getService(true /*wait*/);
+ if (sServiceHidl != null) {
+ sServiceHidl.linkToDeath(sDeathListenerHidl, MEDIA_CAS_HIDL_COOKIE);
+ }
+ return sServiceHidl;
+ } catch (Exception eV1_0) {
+ Log.d(TAG, "Failed to get cas@1.0 service");
+ }
+ }
+ }
+ // Couldn't find an HIDL service, returning null.
+ return null;
}
private void validateInternalStates() {
@@ -756,7 +792,7 @@ public final class MediaCas implements AutoCloseable {
* @return Whether the specified CA system is supported on this device.
*/
public static boolean isSystemIdSupported(int CA_system_id) {
- IMediaCasService service = sService.get();
+ IMediaCasService service = getService();
if (service != null) {
try {
return service.isSystemIdSupported(CA_system_id);
@@ -765,7 +801,7 @@ public final class MediaCas implements AutoCloseable {
}
}
- android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+ android.hardware.cas.V1_0.IMediaCasService serviceHidl = getServiceHidl();
if (serviceHidl != null) {
try {
return serviceHidl.isSystemIdSupported(CA_system_id);
@@ -781,7 +817,7 @@ public final class MediaCas implements AutoCloseable {
* @return an array of descriptors for the available CA plugins.
*/
public static PluginDescriptor[] enumeratePlugins() {
- IMediaCasService service = sService.get();
+ IMediaCasService service = getService();
if (service != null) {
try {
AidlCasPluginDescriptor[] descriptors = service.enumeratePlugins();
@@ -794,10 +830,11 @@ public final class MediaCas implements AutoCloseable {
}
return results;
} catch (RemoteException e) {
+ Log.e(TAG, "Some exception while enumerating plugins");
}
}
- android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+ android.hardware.cas.V1_0.IMediaCasService serviceHidl = getServiceHidl();
if (serviceHidl != null) {
try {
ArrayList<HidlCasPluginDescriptor> descriptors = serviceHidl.enumeratePlugins();
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index e0e198ae551d..45bf5c415a7e 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -5099,7 +5099,7 @@ final public class MediaCodec {
* size is larger than 16x16, then the qpOffset information of all 16x16 blocks that
* encompass the coding unit is combined and used. The QP of target block will be calculated
* as 'frameQP + offsetQP'. If the result exceeds minQP or maxQP configured then the value
- * may be clamped. Negative offset results in blocks encoded at lower QP than frame QP and
+ * will be clamped. Negative offset results in blocks encoded at lower QP than frame QP and
* positive offsets will result in encoding blocks at higher QP than frame QP. If the areas
* of negative QP and positive QP are chosen wisely, the overall viewing experience can be
* improved.
@@ -5126,7 +5126,7 @@ final public class MediaCodec {
* quantization parameter (QP) offset of the blocks in the bounding box. The bounding box
* will get stretched outwards to align to LCU boundaries during encoding. The Qp Offset is
* integral and shall be in the range [-128, 127]. The QP of target block will be calculated
- * as frameQP + offsetQP. If the result exceeds minQP or maxQP configured then the value may
+ * as frameQP + offsetQP. If the result exceeds minQP or maxQP configured then the value will
* be clamped. Negative offset results in blocks encoded at lower QP than frame QP and
* positive offsets will result in blocks encoded at higher QP than frame QP. If the areas of
* negative QP and positive QP are chosen wisely, the overall viewing experience can be
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 1e7bc4764dd7..abad46046890 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2651,11 +2651,10 @@ public final class MediaCodecInfo {
mBlockAspectRatioRange = POSITIVE_RATIONALS;
mAspectRatioRange = POSITIVE_RATIONALS;
- // YUV 4:2:0 requires 2:2 alignment
- mWidthAlignment = 2;
- mHeightAlignment = 2;
- mBlockWidth = 2;
- mBlockHeight = 2;
+ mWidthAlignment = 1;
+ mHeightAlignment = 1;
+ mBlockWidth = 1;
+ mBlockHeight = 1;
mSmallerDimensionUpperLimit = getSizeRange().getUpper();
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 7b83842a9fb2..cd0654ceb348 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -17,6 +17,7 @@
package android.media;
import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
+import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import static com.android.media.codec.flags.Flags.FLAG_CODEC_IMPORTANCE;
import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
@@ -26,6 +27,8 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.Rect;
+import android.text.TextUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -34,6 +37,7 @@ import java.nio.ByteOrder;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -1769,6 +1773,67 @@ public final class MediaFormat {
@FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
public static final String KEY_SECURITY_MODEL = "security-model";
+ /**
+ * QpOffsetRect constitutes the metadata required for encoding a region of interest in an
+ * image or a video frame. The region of interest is represented by a rectangle. The four
+ * integer coordinates of the rectangle are stored in fields left, top, right, bottom.
+ * Note that the right and bottom coordinates are exclusive.
+ * This is paired with a suggestive qp offset information that is to be used during encoding
+ * of the blocks belonging to the to the box.
+ */
+ @FlaggedApi(FLAG_REGION_OF_INTEREST)
+ public static final class QpOffsetRect {
+ private Rect mContour;
+ private int mQpOffset;
+
+ /**
+ * Create a new region of interest with the specified coordinates and qpOffset. Note: no
+ * range checking is performed, so the caller must ensure that left >= 0, left <= right,
+ * top >= 0 and top <= bottom. Note that the right and bottom coordinates are exclusive.
+ *
+ * @param contour Rectangle specifying the region of interest
+ * @param qpOffset qpOffset to be used for the blocks in the specified rectangle
+ */
+ public QpOffsetRect(@NonNull Rect contour, int qpOffset) {
+ mContour = contour;
+ mQpOffset = qpOffset;
+ }
+
+ /**
+ * Update the region of interest information with the specified coordinates and qpOffset
+ *
+ * @param contour Rectangle specifying the region of interest
+ * @param qpOffset qpOffset to be used for the blocks in the specified rectangle
+ */
+ public void set(@NonNull Rect contour, int qpOffset) {
+ mContour = contour;
+ mQpOffset = qpOffset;
+ }
+
+ /**
+ * @return Return a string representation of qpOffsetRect in a compact form.
+ * Helper function to insert key {@link #PARAMETER_KEY_QP_OFFSET_RECTS} in MediaFormat
+ */
+ @NonNull
+ public String flattenToString() {
+ return TextUtils.formatSimple("%d,%d-%d,%d=%d;", mContour.top, mContour.left,
+ mContour.bottom, mContour.right, mQpOffset);
+ }
+
+ /**
+ * @return Return a string representation of qpOffsetRect in a compact form.
+ * Helper function to insert key {@link #PARAMETER_KEY_QP_OFFSET_RECTS} in MediaFormat
+ */
+ @NonNull
+ public static String flattenToString(@NonNull List<QpOffsetRect> qpOffsetRects) {
+ StringBuilder builder = new StringBuilder();
+ for (QpOffsetRect qpOffsetRect : qpOffsetRects) {
+ builder.append(qpOffsetRect.flattenToString());
+ }
+ return builder.toString();
+ }
+ }
+
/* package private */ MediaFormat(@NonNull Map<String, Object> map) {
mMap = map;
}
diff --git a/media/java/android/media/browse/OWNERS b/media/java/android/media/browse/OWNERS
deleted file mode 100644
index 916fc36ffbc6..000000000000
--- a/media/java/android/media/browse/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Bug component: 137631
-
-hdmoon@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
-klhyun@google.com
-gyumin@google.com
diff --git a/media/java/android/media/session/OWNERS b/media/java/android/media/session/OWNERS
deleted file mode 100644
index 916fc36ffbc6..000000000000
--- a/media/java/android/media/session/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Bug component: 137631
-
-hdmoon@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
-klhyun@google.com
-gyumin@google.com
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index 25040a942061..e872a58c96cf 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -86,7 +86,7 @@ public:
}
// Retrieves the associated object, returns nullValue T if not available.
- T get(JNIEnv *env, jobject thiz) {
+ T get(JNIEnv *env, jobject thiz) const {
std::lock_guard lg(mLock);
// NOLINTNEXTLINE(performance-no-int-to-ptr)
auto ptr = reinterpret_cast<T*>(env->GetLongField(thiz, mFieldId));
@@ -167,8 +167,10 @@ private:
// is possible by checking if the WeakGlobalRef is null equivalent.
auto& getSoundPoolManager() {
- static ObjectManager<std::shared_ptr<SoundPool>> soundPoolManager(fields.mNativeContext);
- return soundPoolManager;
+ // never-delete singleton
+ static auto soundPoolManager =
+ new ObjectManager<std::shared_ptr<SoundPool>>(fields.mNativeContext);
+ return *soundPoolManager;
}
inline auto getSoundPool(JNIEnv *env, jobject thiz) {
@@ -274,8 +276,9 @@ static_assert(std::is_same_v<JWeakValue*, jweak>);
auto& getSoundPoolJavaRefManager() {
// Note this can store shared_ptrs to either jweak and jobject,
// as the underlying type is identical.
- static ConcurrentHashMap<SoundPool *, std::shared_ptr<JWeakValue>> concurrentHashMap;
- return concurrentHashMap;
+ static auto concurrentHashMap =
+ new ConcurrentHashMap<SoundPool *, std::shared_ptr<JWeakValue>>();
+ return *concurrentHashMap;
}
// make_shared_globalref_from_localref() creates a sharable Java global
diff --git a/nfc/Android.bp b/nfc/Android.bp
index 2090d3397dfe..3909e1d3b807 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -69,6 +69,9 @@ java_sdk_library {
lint: {
strict_updatability_linting: true,
},
+ aconfig_declarations: [
+ "android.nfc.flags-aconfig",
+ ],
}
filegroup {
diff --git a/packages/CrashRecovery/OWNERS b/packages/CrashRecovery/OWNERS
index daa02111f71f..8337fd2453df 100644
--- a/packages/CrashRecovery/OWNERS
+++ b/packages/CrashRecovery/OWNERS
@@ -1,3 +1 @@
-ancr@google.com
-harshitmahajan@google.com
-robertogil@google.com
+include /services/core/java/com/android/server/crashrecovery/OWNERS \ No newline at end of file
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
index 5d71b7d98fdc..a8d8f9a1a55d 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
import android.net.ConnectivityModuleConnector;
import android.os.Environment;
import android.os.Handler;
@@ -38,15 +39,15 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.BackgroundThread;
-import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.Xml;
+import android.utils.BackgroundThread;
+import android.utils.LongArrayQueue;
+import android.utils.XmlUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -57,16 +58,20 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -130,8 +135,25 @@ public class PackageWatchdog {
@VisibleForTesting
static final int DEFAULT_BOOT_LOOP_TRIGGER_COUNT = 5;
- @VisibleForTesting
+
static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
+ // Boot loop at which packageWatchdog starts first mitigation
+ private static final String BOOT_LOOP_THRESHOLD =
+ "persist.device_config.configuration.boot_loop_threshold";
+ @VisibleForTesting
+ static final int DEFAULT_BOOT_LOOP_THRESHOLD = 15;
+ // Once boot_loop_threshold is surpassed next mitigation would be triggered after
+ // specified number of reboots.
+ private static final String BOOT_LOOP_MITIGATION_INCREMENT =
+ "persist.device_config.configuration..boot_loop_mitigation_increment";
+ @VisibleForTesting
+ static final int DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT = 2;
+
+ // Threshold level at which or above user might experience significant disruption.
+ private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
+ "persist.device_config.configuration.major_user_impact_level_threshold";
+ private static final int DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
private long mNumberOfNativeCrashPollsRemaining;
@@ -145,6 +167,7 @@ public class PackageWatchdog {
private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration";
private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check";
private static final String ATTR_MITIGATION_CALLS = "mitigation-calls";
+ private static final String ATTR_MITIGATION_COUNT = "mitigation-count";
// A file containing information about the current mitigation count in the case of a boot loop.
// This allows boot loop information to persist in the case of an fs-checkpoint being
@@ -230,8 +253,16 @@ public class PackageWatchdog {
mConnectivityModuleConnector = connectivityModuleConnector;
mSystemClock = clock;
mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
- mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
- DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS);
+ if (Flags.recoverabilityDetection()) {
+ mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ SystemProperties.getInt(BOOT_LOOP_MITIGATION_INCREMENT,
+ DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+ } else {
+ mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS);
+ }
+
loadFromFile();
sPackageWatchdog = this;
}
@@ -436,8 +467,13 @@ public class PackageWatchdog {
mitigationCount =
currentMonitoredPackage.getMitigationCountLocked();
}
- currentObserverToNotify.execute(versionedPackage,
- failureReason, mitigationCount);
+ if (Flags.recoverabilityDetection()) {
+ maybeExecute(currentObserverToNotify, versionedPackage,
+ failureReason, currentObserverImpact, mitigationCount);
+ } else {
+ currentObserverToNotify.execute(versionedPackage,
+ failureReason, mitigationCount);
+ }
}
}
}
@@ -467,37 +503,76 @@ public class PackageWatchdog {
}
}
if (currentObserverToNotify != null) {
- currentObserverToNotify.execute(failingPackage, failureReason, 1);
+ if (Flags.recoverabilityDetection()) {
+ maybeExecute(currentObserverToNotify, failingPackage, failureReason,
+ currentObserverImpact, /*mitigationCount=*/ 1);
+ } else {
+ currentObserverToNotify.execute(failingPackage, failureReason, 1);
+ }
+ }
+ }
+
+ private void maybeExecute(PackageHealthObserver currentObserverToNotify,
+ VersionedPackage versionedPackage,
+ @FailureReasons int failureReason,
+ int currentObserverImpact,
+ int mitigationCount) {
+ if (currentObserverImpact < getUserImpactLevelLimit()) {
+ currentObserverToNotify.execute(versionedPackage, failureReason, mitigationCount);
}
}
+
/**
* Called when the system server boots. If the system server is detected to be in a boot loop,
* query each observer and perform the mitigation action with the lowest user impact.
*/
+ @SuppressWarnings("GuardedBy")
public void noteBoot() {
synchronized (mLock) {
- if (mBootThreshold.incrementAndTest()) {
- mBootThreshold.reset();
+ boolean mitigate = mBootThreshold.incrementAndTest();
+ if (mitigate) {
+ if (!Flags.recoverabilityDetection()) {
+ mBootThreshold.reset();
+ }
int mitigationCount = mBootThreshold.getMitigationCount() + 1;
PackageHealthObserver currentObserverToNotify = null;
+ ObserverInternal currentObserverInternal = null;
int currentObserverImpact = Integer.MAX_VALUE;
for (int i = 0; i < mAllObservers.size(); i++) {
final ObserverInternal observer = mAllObservers.valueAt(i);
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null) {
- int impact = registeredObserver.onBootLoop(mitigationCount);
+ int impact = Flags.recoverabilityDetection()
+ ? registeredObserver.onBootLoop(
+ observer.getBootMitigationCount() + 1)
+ : registeredObserver.onBootLoop(mitigationCount);
if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
&& impact < currentObserverImpact) {
currentObserverToNotify = registeredObserver;
+ currentObserverInternal = observer;
currentObserverImpact = impact;
}
}
}
if (currentObserverToNotify != null) {
- mBootThreshold.setMitigationCount(mitigationCount);
- mBootThreshold.saveMitigationCountToMetadata();
- currentObserverToNotify.executeBootLoopMitigation(mitigationCount);
+ if (Flags.recoverabilityDetection()) {
+ if (currentObserverImpact < getUserImpactLevelLimit()
+ || (currentObserverImpact >= getUserImpactLevelLimit()
+ && mBootThreshold.getCount() >= getBootLoopThreshold())) {
+ int currentObserverMitigationCount =
+ currentObserverInternal.getBootMitigationCount() + 1;
+ currentObserverInternal.setBootMitigationCount(
+ currentObserverMitigationCount);
+ saveAllObserversBootMitigationCountToMetadata(METADATA_FILE);
+ currentObserverToNotify.executeBootLoopMitigation(
+ currentObserverMitigationCount);
+ }
+ } else {
+ mBootThreshold.setMitigationCount(mitigationCount);
+ mBootThreshold.saveMitigationCountToMetadata();
+ currentObserverToNotify.executeBootLoopMitigation(mitigationCount);
+ }
}
}
}
@@ -567,13 +642,27 @@ public class PackageWatchdog {
mShortTaskHandler.post(()->checkAndMitigateNativeCrashes());
}
+ private int getUserImpactLevelLimit() {
+ return SystemProperties.getInt(MAJOR_USER_IMPACT_LEVEL_THRESHOLD,
+ DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD);
+ }
+
+ private int getBootLoopThreshold() {
+ return SystemProperties.getInt(BOOT_LOOP_THRESHOLD,
+ DEFAULT_BOOT_LOOP_THRESHOLD);
+ }
+
/** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */
@Retention(SOURCE)
@IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_10,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_50,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_71,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_75,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_80,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_90,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_100})
public @interface PackageHealthObserverImpact {
@@ -582,11 +671,15 @@ public class PackageWatchdog {
/* Action has low user impact, user of a device will barely notice. */
int USER_IMPACT_LEVEL_10 = 10;
/* Actions having medium user impact, user of a device will likely notice. */
+ int USER_IMPACT_LEVEL_20 = 20;
int USER_IMPACT_LEVEL_30 = 30;
int USER_IMPACT_LEVEL_50 = 50;
int USER_IMPACT_LEVEL_70 = 70;
- int USER_IMPACT_LEVEL_90 = 90;
/* Action has high user impact, a last resort, user of a device will be very frustrated. */
+ int USER_IMPACT_LEVEL_71 = 71;
+ int USER_IMPACT_LEVEL_75 = 75;
+ int USER_IMPACT_LEVEL_80 = 80;
+ int USER_IMPACT_LEVEL_90 = 90;
int USER_IMPACT_LEVEL_100 = 100;
}
@@ -1144,6 +1237,12 @@ public class PackageWatchdog {
}
}
+ @VisibleForTesting
+ @GuardedBy("mLock")
+ void registerObserverInternal(ObserverInternal observerInternal) {
+ mAllObservers.put(observerInternal.name, observerInternal);
+ }
+
/**
* Represents an observer monitoring a set of packages along with the failure thresholds for
* each package.
@@ -1151,17 +1250,23 @@ public class PackageWatchdog {
* <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
* instances of this class.
*/
- private static class ObserverInternal {
+ static class ObserverInternal {
public final String name;
@GuardedBy("mLock")
private final ArrayMap<String, MonitoredPackage> mPackages = new ArrayMap<>();
@Nullable
@GuardedBy("mLock")
public PackageHealthObserver registeredObserver;
+ private int mMitigationCount;
ObserverInternal(String name, List<MonitoredPackage> packages) {
+ this(name, packages, /*mitigationCount=*/ 0);
+ }
+
+ ObserverInternal(String name, List<MonitoredPackage> packages, int mitigationCount) {
this.name = name;
updatePackagesLocked(packages);
+ this.mMitigationCount = mitigationCount;
}
/**
@@ -1173,6 +1278,9 @@ public class PackageWatchdog {
try {
out.startTag(null, TAG_OBSERVER);
out.attribute(null, ATTR_NAME, name);
+ if (Flags.recoverabilityDetection()) {
+ out.attributeInt(null, ATTR_MITIGATION_COUNT, mMitigationCount);
+ }
for (int i = 0; i < mPackages.size(); i++) {
MonitoredPackage p = mPackages.valueAt(i);
p.writeLocked(out);
@@ -1185,6 +1293,14 @@ public class PackageWatchdog {
}
}
+ public int getBootMitigationCount() {
+ return mMitigationCount;
+ }
+
+ public void setBootMitigationCount(int mitigationCount) {
+ mMitigationCount = mitigationCount;
+ }
+
@GuardedBy("mLock")
public void updatePackagesLocked(List<MonitoredPackage> packages) {
for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
@@ -1289,6 +1405,7 @@ public class PackageWatchdog {
**/
public static ObserverInternal read(TypedXmlPullParser parser, PackageWatchdog watchdog) {
String observerName = null;
+ int observerMitigationCount = 0;
if (TAG_OBSERVER.equals(parser.getName())) {
observerName = parser.getAttributeValue(null, ATTR_NAME);
if (TextUtils.isEmpty(observerName)) {
@@ -1299,6 +1416,9 @@ public class PackageWatchdog {
List<MonitoredPackage> packages = new ArrayList<>();
int innerDepth = parser.getDepth();
try {
+ if (Flags.recoverabilityDetection()) {
+ observerMitigationCount = parser.getAttributeInt(null, ATTR_MITIGATION_COUNT);
+ }
while (XmlUtils.nextElementWithin(parser, innerDepth)) {
if (TAG_PACKAGE.equals(parser.getName())) {
try {
@@ -1319,7 +1439,7 @@ public class PackageWatchdog {
if (packages.isEmpty()) {
return null;
}
- return new ObserverInternal(observerName, packages);
+ return new ObserverInternal(observerName, packages, observerMitigationCount);
}
/** Dumps information about this observer and the packages it watches. */
@@ -1679,6 +1799,27 @@ public class PackageWatchdog {
}
}
+ @GuardedBy("mLock")
+ @SuppressWarnings("GuardedBy")
+ void saveAllObserversBootMitigationCountToMetadata(String filePath) {
+ HashMap<String, Integer> bootMitigationCounts = new HashMap<>();
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ final ObserverInternal observer = mAllObservers.valueAt(i);
+ bootMitigationCounts.put(observer.name, observer.getBootMitigationCount());
+ }
+
+ try {
+ FileOutputStream fileStream = new FileOutputStream(new File(filePath));
+ ObjectOutputStream objectStream = new ObjectOutputStream(fileStream);
+ objectStream.writeObject(bootMitigationCounts);
+ objectStream.flush();
+ objectStream.close();
+ fileStream.close();
+ } catch (Exception e) {
+ Slog.i(TAG, "Could not save observers metadata to file: " + e);
+ }
+ }
+
/**
* Handles the thresholding logic for system server boots.
*/
@@ -1686,10 +1827,16 @@ public class PackageWatchdog {
private final int mBootTriggerCount;
private final long mTriggerWindow;
+ private final int mBootMitigationIncrement;
BootThreshold(int bootTriggerCount, long triggerWindow) {
+ this(bootTriggerCount, triggerWindow, /*bootMitigationIncrement=*/ 1);
+ }
+
+ BootThreshold(int bootTriggerCount, long triggerWindow, int bootMitigationIncrement) {
this.mBootTriggerCount = bootTriggerCount;
this.mTriggerWindow = triggerWindow;
+ this.mBootMitigationIncrement = bootMitigationIncrement;
}
public void reset() {
@@ -1761,8 +1908,13 @@ public class PackageWatchdog {
/** Increments the boot counter, and returns whether the device is bootlooping. */
+ @GuardedBy("mLock")
public boolean incrementAndTest() {
- readMitigationCountFromMetadataIfNecessary();
+ if (Flags.recoverabilityDetection()) {
+ readAllObserversBootMitigationCountIfNecessary(METADATA_FILE);
+ } else {
+ readMitigationCountFromMetadataIfNecessary();
+ }
final long now = mSystemClock.uptimeMillis();
if (now - getStart() < 0) {
Slog.e(TAG, "Window was less than zero. Resetting start to current time.");
@@ -1770,8 +1922,12 @@ public class PackageWatchdog {
setMitigationStart(now);
}
if (now - getMitigationStart() > DEFAULT_DEESCALATION_WINDOW_MS) {
- setMitigationCount(0);
setMitigationStart(now);
+ if (Flags.recoverabilityDetection()) {
+ resetAllObserversBootMitigationCount();
+ } else {
+ setMitigationCount(0);
+ }
}
final long window = now - getStart();
if (window >= mTriggerWindow) {
@@ -1782,9 +1938,48 @@ public class PackageWatchdog {
int count = getCount() + 1;
setCount(count);
EventLogTags.writeRescueNote(Process.ROOT_UID, count, window);
+ if (Flags.recoverabilityDetection()) {
+ boolean mitigate = (count >= mBootTriggerCount)
+ && (count - mBootTriggerCount) % mBootMitigationIncrement == 0;
+ return mitigate;
+ }
return count >= mBootTriggerCount;
}
}
+ @GuardedBy("mLock")
+ private void resetAllObserversBootMitigationCount() {
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ final ObserverInternal observer = mAllObservers.valueAt(i);
+ observer.setBootMitigationCount(0);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @SuppressWarnings("GuardedBy")
+ void readAllObserversBootMitigationCountIfNecessary(String filePath) {
+ File metadataFile = new File(filePath);
+ if (metadataFile.exists()) {
+ try {
+ FileInputStream fileStream = new FileInputStream(metadataFile);
+ ObjectInputStream objectStream = new ObjectInputStream(fileStream);
+ HashMap<String, Integer> bootMitigationCounts =
+ (HashMap<String, Integer>) objectStream.readObject();
+ objectStream.close();
+ fileStream.close();
+
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ final ObserverInternal observer = mAllObservers.valueAt(i);
+ if (bootMitigationCounts.containsKey(observer.name)) {
+ observer.setBootMitigationCount(
+ bootMitigationCounts.get(observer.name));
+ }
+ }
+ } catch (Exception e) {
+ Slog.i(TAG, "Could not read observer metadata file: " + e);
+ }
+ }
+ }
+
}
}
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
index 9217e7012e7e..7093ba42f40d 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
@@ -20,6 +20,7 @@ import static android.provider.DeviceConfig.Properties;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -27,9 +28,9 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
import android.os.Build;
import android.os.Environment;
-import android.os.FileUtils;
import android.os.PowerManager;
import android.os.RecoverySystem;
import android.os.SystemClock;
@@ -42,10 +43,11 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import android.utils.ArrayUtils;
+import android.utils.FileUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.server.PackageWatchdog.FailureReasons;
import com.android.server.PackageWatchdog.PackageHealthObserver;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
@@ -53,6 +55,8 @@ import com.android.server.am.SettingsToPropertiesMapper;
import com.android.server.crashrecovery.proto.CrashRecoveryStatsLog;
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;
@@ -89,6 +93,40 @@ public class RescueParty {
@VisibleForTesting
static final int LEVEL_FACTORY_RESET = 5;
@VisibleForTesting
+ static final int RESCUE_LEVEL_NONE = 0;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET = 1;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET = 2;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_WARM_REBOOT = 3;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 4;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 5;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 6;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_FACTORY_RESET = 7;
+
+ @IntDef(prefix = { "RESCUE_LEVEL_" }, value = {
+ RESCUE_LEVEL_NONE,
+ RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET,
+ RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET,
+ RESCUE_LEVEL_WARM_REBOOT,
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
+ RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
+ RESCUE_LEVEL_FACTORY_RESET
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RescueLevels {}
+
+ @VisibleForTesting
+ static final String RESCUE_NON_REBOOT_LEVEL_LIMIT = "persist.sys.rescue_non_reboot_level_limit";
+ @VisibleForTesting
+ static final int DEFAULT_RESCUE_NON_REBOOT_LEVEL_LIMIT = RESCUE_LEVEL_WARM_REBOOT - 1;
+ @VisibleForTesting
static final String TAG = "RescueParty";
@VisibleForTesting
static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
@@ -163,10 +201,8 @@ public class RescueParty {
* Check if we're currently attempting to reboot for a factory reset. This method must
* return true if RescueParty tries to reboot early during a boot loop, since the device
* will not be fully booted at this time.
- *
- * TODO(gavincorkery): Rename method since its scope has expanded.
*/
- public static boolean isAttemptingFactoryReset() {
+ public static boolean isRecoveryTriggeredReboot() {
return isFactoryResetPropertySet() || isRebootPropertySet();
}
@@ -349,11 +385,20 @@ public class RescueParty {
}
private static int getMaxRescueLevel(boolean mayPerformReboot) {
- if (!mayPerformReboot
- || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
- return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+ if (Flags.recoverabilityDetection()) {
+ if (!mayPerformReboot
+ || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+ return SystemProperties.getInt(RESCUE_NON_REBOOT_LEVEL_LIMIT,
+ DEFAULT_RESCUE_NON_REBOOT_LEVEL_LIMIT);
+ }
+ return RESCUE_LEVEL_FACTORY_RESET;
+ } else {
+ if (!mayPerformReboot
+ || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+ return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+ }
+ return LEVEL_FACTORY_RESET;
}
- return LEVEL_FACTORY_RESET;
}
/**
@@ -381,6 +426,46 @@ public class RescueParty {
}
}
+ /**
+ * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
+ * When failedPackage is null then 1st and 2nd mitigation counts are redundant (scoped and
+ * all device config reset). Behaves as if one mitigation attempt was already done.
+ *
+ * @param mitigationCount the mitigation attempt number (1 = first attempt etc.).
+ * @param mayPerformReboot whether or not a reboot and factory reset may be performed
+ * for the given failure.
+ * @param failedPackage in case of bootloop this is null.
+ * @return the rescue level for the n-th mitigation attempt.
+ */
+ private static @RescueLevels int getRescueLevel(int mitigationCount, boolean mayPerformReboot,
+ @Nullable VersionedPackage failedPackage) {
+ // Skipping RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET since it's not defined without a failed
+ // package.
+ if (failedPackage == null && mitigationCount > 0) {
+ mitigationCount += 1;
+ }
+ if (mitigationCount == 1) {
+ return RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET;
+ } else if (mitigationCount == 2) {
+ return RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET;
+ } else if (mitigationCount == 3) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_WARM_REBOOT);
+ } else if (mitigationCount == 4) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot),
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
+ } else if (mitigationCount == 5) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot),
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES);
+ } else if (mitigationCount == 6) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot),
+ RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS);
+ } else if (mitigationCount >= 7) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_FACTORY_RESET);
+ } else {
+ return RESCUE_LEVEL_NONE;
+ }
+ }
+
private static void executeRescueLevel(Context context, @Nullable String failedPackage,
int level) {
Slog.w(TAG, "Attempting rescue level " + levelToString(level));
@@ -399,6 +484,15 @@ public class RescueParty {
private static void executeRescueLevelInternal(Context context, int level, @Nullable
String failedPackage) throws Exception {
+ if (Flags.recoverabilityDetection()) {
+ executeRescueLevelInternalNew(context, level, failedPackage);
+ } else {
+ executeRescueLevelInternalOld(context, level, failedPackage);
+ }
+ }
+
+ private static void executeRescueLevelInternalOld(Context context, int level, @Nullable
+ String failedPackage) throws Exception {
if (level <= LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS) {
// Disabling flag resets on master branch for trunk stable launch.
@@ -412,8 +506,6 @@ public class RescueParty {
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
Exception res = null;
- Runnable runnable;
- Thread thread;
switch (level) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
try {
@@ -455,21 +547,7 @@ public class RescueParty {
}
break;
case LEVEL_WARM_REBOOT:
- // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
- // when device shutting down.
- setRebootProperty(true);
- runnable = () -> {
- try {
- PowerManager pm = context.getSystemService(PowerManager.class);
- if (pm != null) {
- pm.reboot(TAG);
- }
- } catch (Throwable t) {
- logRescueException(level, failedPackage, t);
- }
- };
- thread = new Thread(runnable);
- thread.start();
+ executeWarmReboot(context, level, failedPackage);
break;
case LEVEL_FACTORY_RESET:
// Before the completion of Reboot, if any crash happens then PackageWatchdog
@@ -477,23 +555,9 @@ public class RescueParty {
// Adding a check to prevent factory reset to execute before above reboot completes.
// Note: this reboot property is not persistent resets after reboot is completed.
if (isRebootPropertySet()) {
- break;
+ return;
}
- setFactoryResetProperty(true);
- long now = System.currentTimeMillis();
- setLastFactoryResetTimeMs(now);
- runnable = new Runnable() {
- @Override
- public void run() {
- try {
- RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
- } catch (Throwable t) {
- logRescueException(level, failedPackage, t);
- }
- }
- };
- thread = new Thread(runnable);
- thread.start();
+ executeFactoryReset(context, level, failedPackage);
break;
}
@@ -502,6 +566,83 @@ public class RescueParty {
}
}
+ private static void executeRescueLevelInternalNew(Context context, @RescueLevels int level,
+ @Nullable String failedPackage) throws Exception {
+ CrashRecoveryStatsLog.write(CrashRecoveryStatsLog.RESCUE_PARTY_RESET_REPORTED,
+ level, levelToString(level));
+ switch (level) {
+ case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+ // Temporary disable deviceConfig reset
+ // resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
+ break;
+ case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+ // Temporary disable deviceConfig reset
+ // 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);
+ break;
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, level);
+ break;
+ case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ 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
+ // escalates to next level i.e. factory reset, as they happen in separate threads.
+ // Adding a check to prevent factory reset to execute before above reboot completes.
+ // Note: this reboot property is not persistent resets after reboot is completed.
+ if (isRebootPropertySet()) {
+ return;
+ }
+ executeFactoryReset(context, level, failedPackage);
+ break;
+ }
+ }
+
+ private static void executeWarmReboot(Context context, int level,
+ @Nullable String failedPackage) {
+ // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
+ // when device shutting down.
+ setRebootProperty(true);
+ Runnable runnable = () -> {
+ try {
+ PowerManager pm = context.getSystemService(PowerManager.class);
+ if (pm != null) {
+ pm.reboot(TAG);
+ }
+ } catch (Throwable t) {
+ logRescueException(level, failedPackage, t);
+ }
+ };
+ Thread thread = new Thread(runnable);
+ thread.start();
+ }
+
+ private static void executeFactoryReset(Context context, int level,
+ @Nullable String failedPackage) {
+ setFactoryResetProperty(true);
+ long now = System.currentTimeMillis();
+ setLastFactoryResetTimeMs(now);
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
+ } catch (Throwable t) {
+ logRescueException(level, failedPackage, t);
+ }
+ }
+ };
+ Thread thread = new Thread(runnable);
+ thread.start();
+ }
+
+
private static String getCompleteMessage(Throwable t) {
final StringBuilder builder = new StringBuilder();
builder.append(t.getMessage());
@@ -523,17 +664,38 @@ public class RescueParty {
}
private static int mapRescueLevelToUserImpact(int rescueLevel) {
- switch(rescueLevel) {
- case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
- case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
- case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
- case LEVEL_WARM_REBOOT:
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
- case LEVEL_FACTORY_RESET:
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
- default:
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ if (Flags.recoverabilityDetection()) {
+ switch (rescueLevel) {
+ case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
+ case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_20;
+ case RESCUE_LEVEL_WARM_REBOOT:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_75;
+ case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_80;
+ case RESCUE_LEVEL_FACTORY_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
+ default:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ }
+ } else {
+ switch (rescueLevel) {
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
+ case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ case LEVEL_WARM_REBOOT:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
+ case LEVEL_FACTORY_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
+ default:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ }
}
}
@@ -550,7 +712,7 @@ public class RescueParty {
final ContentResolver resolver = context.getContentResolver();
try {
Settings.Global.resetToDefaultsAsUser(resolver, null, mode,
- UserHandle.SYSTEM.getIdentifier());
+ UserHandle.SYSTEM.getIdentifier());
} catch (Exception e) {
res = new RuntimeException("Failed to reset global settings", e);
}
@@ -669,8 +831,13 @@ public class RescueParty {
@FailureReasons int failureReason, int mitigationCount) {
if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ if (Flags.recoverabilityDetection()) {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ mayPerformReboot(failedPackage), failedPackage));
+ } else {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
mayPerformReboot(failedPackage)));
+ }
} else {
return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
}
@@ -684,8 +851,10 @@ public class RescueParty {
}
if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
- final int level = getRescueLevel(mitigationCount,
- mayPerformReboot(failedPackage));
+ final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount,
+ mayPerformReboot(failedPackage), failedPackage)
+ : getRescueLevel(mitigationCount,
+ mayPerformReboot(failedPackage));
executeRescueLevel(mContext,
failedPackage == null ? null : failedPackage.getPackageName(), level);
return true;
@@ -707,7 +876,7 @@ public class RescueParty {
if (pm.getModuleInfo(packageName, 0) != null) {
return true;
}
- } catch (PackageManager.NameNotFoundException ignore) {
+ } catch (PackageManager.NameNotFoundException | IllegalStateException ignore) {
}
return isPersistentSystemApp(packageName);
@@ -718,7 +887,12 @@ public class RescueParty {
if (isDisabled()) {
return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
}
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
+ if (Flags.recoverabilityDetection()) {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ true, /*failedPackage=*/ null));
+ } else {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
+ }
}
@Override
@@ -727,8 +901,10 @@ public class RescueParty {
return false;
}
boolean mayPerformReboot = !shouldThrottleReboot();
- executeRescueLevel(mContext, /*failedPackage=*/ null,
- getRescueLevel(mitigationCount, mayPerformReboot));
+ final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount,
+ mayPerformReboot, /*failedPackage=*/ null)
+ : getRescueLevel(mitigationCount, mayPerformReboot);
+ executeRescueLevel(mContext, /*failedPackage=*/ null, level);
return true;
}
@@ -845,14 +1021,44 @@ public class RescueParty {
}
private static String levelToString(int level) {
- switch (level) {
- case LEVEL_NONE: return "NONE";
- case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
- case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES";
- case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS";
- case LEVEL_WARM_REBOOT: return "WARM_REBOOT";
- case LEVEL_FACTORY_RESET: return "FACTORY_RESET";
- default: return Integer.toString(level);
+ if (Flags.recoverabilityDetection()) {
+ switch (level) {
+ case RESCUE_LEVEL_NONE:
+ return "NONE";
+ case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+ return "SCOPED_DEVICE_CONFIG_RESET";
+ case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+ return "ALL_DEVICE_CONFIG_RESET";
+ case RESCUE_LEVEL_WARM_REBOOT:
+ return "WARM_REBOOT";
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return "RESET_SETTINGS_UNTRUSTED_CHANGES";
+ case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ return "RESET_SETTINGS_TRUSTED_DEFAULTS";
+ case RESCUE_LEVEL_FACTORY_RESET:
+ return "FACTORY_RESET";
+ default:
+ return Integer.toString(level);
+ }
+ } else {
+ switch (level) {
+ case LEVEL_NONE:
+ return "NONE";
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return "RESET_SETTINGS_UNTRUSTED_CHANGES";
+ case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ return "RESET_SETTINGS_TRUSTED_DEFAULTS";
+ case LEVEL_WARM_REBOOT:
+ return "WARM_REBOOT";
+ case LEVEL_FACTORY_RESET:
+ return "FACTORY_RESET";
+ default:
+ return Integer.toString(level);
+ }
}
}
}
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 0fb932735ab4..93f26aefb692 100644
--- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -69,7 +69,7 @@ import java.util.function.Consumer;
*
* @hide
*/
-final class RollbackPackageHealthObserver implements PackageHealthObserver {
+public final class RollbackPackageHealthObserver implements PackageHealthObserver {
private static final String TAG = "RollbackPackageHealthObserver";
private static final String NAME = "rollback-observer";
private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
@@ -89,7 +89,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
private boolean mTwoPhaseRollbackEnabled;
@VisibleForTesting
- RollbackPackageHealthObserver(Context context, ApexManager apexManager) {
+ public RollbackPackageHealthObserver(Context context, ApexManager apexManager) {
mContext = context;
HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
handlerThread.start();
diff --git a/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java b/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java
new file mode 100644
index 000000000000..fa4d6afc03d3
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java
@@ -0,0 +1,115 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.io.File;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Copied over from frameworks/base/core/java/com/android/internal/util/ArrayUtils.java
+ *
+ * @hide
+ */
+public class ArrayUtils {
+ private ArrayUtils() { /* cannot be instantiated */ }
+ public static final File[] EMPTY_FILE = new File[0];
+
+
+ /**
+ * Return first index of {@code value} in {@code array}, or {@code -1} if
+ * not found.
+ */
+ public static <T> int indexOf(@Nullable T[] array, T value) {
+ if (array == null) return -1;
+ for (int i = 0; i < array.length; i++) {
+ if (Objects.equals(array[i], value)) return i;
+ }
+ return -1;
+ }
+
+ /** @hide */
+ public static @NonNull File[] defeatNullable(@Nullable File[] val) {
+ return (val != null) ? val : EMPTY_FILE;
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(@Nullable int[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * True if the byte array is null or has length 0.
+ */
+ public static boolean isEmpty(@Nullable byte[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Converts from List of bytes to byte array
+ * @param list
+ * @return byte[]
+ */
+ public static byte[] toPrimitive(List<byte[]> list) {
+ if (list.size() == 0) {
+ return new byte[0];
+ }
+ int byteLen = list.get(0).length;
+ byte[] array = new byte[list.size() * byteLen];
+ for (int i = 0; i < list.size(); i++) {
+ for (int j = 0; j < list.get(i).length; j++) {
+ array[i * byteLen + j] = list.get(i)[j];
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Adds value to given array if not already present, providing set-like
+ * behavior.
+ */
+ public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
+ return appendInt(cur, val, false);
+ }
+
+ /**
+ * Adds value to given array.
+ */
+ public static @NonNull int[] appendInt(@Nullable int[] cur, int val,
+ boolean allowDuplicates) {
+ if (cur == null) {
+ return new int[] { val };
+ }
+ final int n = cur.length;
+ if (!allowDuplicates) {
+ for (int i = 0; i < n; i++) {
+ if (cur[i] == val) {
+ return cur;
+ }
+ }
+ }
+ int[] ret = new int[n + 1];
+ System.arraycopy(cur, 0, ret, 0, n);
+ ret[n] = val;
+ return ret;
+ }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java
index a6ae68f62f10..afcf6895fd0d 100644
--- a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
+++ b/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.util;
+package android.utils;
import android.annotation.NonNull;
import android.os.Handler;
diff --git a/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java b/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java
new file mode 100644
index 000000000000..e4923bfc4ecb
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java
@@ -0,0 +1,128 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Bits and pieces copied from hidden API of android.os.FileUtils.
+ *
+ * @hide
+ */
+public class FileUtils {
+ /**
+ * Read a text file into a String, optionally limiting the length.
+ *
+ * @param file to read (will not seek, so things like /proc files are OK)
+ * @param max length (positive for head, negative of tail, 0 for no limit)
+ * @param ellipsis to add of the file was truncated (can be null)
+ * @return the contents of the file, possibly truncated
+ * @throws IOException if something goes wrong reading the file
+ * @hide
+ */
+ public static @Nullable String readTextFile(@Nullable File file, @Nullable int max,
+ @Nullable String ellipsis) throws IOException {
+ InputStream input = new FileInputStream(file);
+ // wrapping a BufferedInputStream around it because when reading /proc with unbuffered
+ // input stream, bytes read not equal to buffer size is not necessarily the correct
+ // indication for EOF; but it is true for BufferedInputStream due to its implementation.
+ BufferedInputStream bis = new BufferedInputStream(input);
+ try {
+ long size = file.length();
+ if (max > 0 || (size > 0 && max == 0)) { // "head" mode: read the first N bytes
+ if (size > 0 && (max == 0 || size < max)) max = (int) size;
+ byte[] data = new byte[max + 1];
+ int length = bis.read(data);
+ if (length <= 0) return "";
+ if (length <= max) return new String(data, 0, length);
+ if (ellipsis == null) return new String(data, 0, max);
+ return new String(data, 0, max) + ellipsis;
+ } else if (max < 0) { // "tail" mode: keep the last N
+ int len;
+ boolean rolled = false;
+ byte[] last = null;
+ byte[] data = null;
+ do {
+ if (last != null) rolled = true;
+ byte[] tmp = last;
+ last = data;
+ data = tmp;
+ if (data == null) data = new byte[-max];
+ len = bis.read(data);
+ } while (len == data.length);
+
+ if (last == null && len <= 0) return "";
+ if (last == null) return new String(data, 0, len);
+ if (len > 0) {
+ rolled = true;
+ System.arraycopy(last, len, last, 0, last.length - len);
+ System.arraycopy(data, 0, last, last.length - len, len);
+ }
+ if (ellipsis == null || !rolled) return new String(last);
+ return ellipsis + new String(last);
+ } else { // "cat" mode: size unknown, read it all in streaming fashion
+ ByteArrayOutputStream contents = new ByteArrayOutputStream();
+ int len;
+ byte[] data = new byte[1024];
+ do {
+ len = bis.read(data);
+ if (len > 0) contents.write(data, 0, len);
+ } while (len == data.length);
+ return contents.toString();
+ }
+ } finally {
+ bis.close();
+ input.close();
+ }
+ }
+
+ /**
+ * Perform an fsync on the given FileOutputStream. The stream at this
+ * point must be flushed but not yet closed.
+ *
+ * @hide
+ */
+ public static boolean sync(FileOutputStream stream) {
+ try {
+ if (stream != null) {
+ stream.getFD().sync();
+ }
+ return true;
+ } catch (IOException e) {
+ }
+ return false;
+ }
+
+ /**
+ * List the files in the directory or return empty file.
+ *
+ * @hide
+ */
+ public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) {
+ return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles())
+ : ArrayUtils.EMPTY_FILE;
+ }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java
index 948ebcca0263..fdb15e2333d5 100644
--- a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
+++ b/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.util;
+package android.utils;
import android.annotation.NonNull;
import android.os.Handler;
diff --git a/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java b/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java
new file mode 100644
index 000000000000..5cdc2536129a
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java
@@ -0,0 +1,188 @@
+/*
+ * 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.utils;
+
+import libcore.util.EmptyArray;
+
+import java.util.NoSuchElementException;
+
+/**
+ * Copied from frameworks/base/core/java/android/util/LongArrayQueue.java
+ *
+ * @hide
+ */
+public class LongArrayQueue {
+
+ private long[] mValues;
+ private int mSize;
+ private int mHead;
+ private int mTail;
+
+ private long[] newUnpaddedLongArray(int num) {
+ return new long[num];
+ }
+ /**
+ * Initializes a queue with the given starting capacity.
+ *
+ * @param initialCapacity the capacity.
+ */
+ public LongArrayQueue(int initialCapacity) {
+ if (initialCapacity == 0) {
+ mValues = EmptyArray.LONG;
+ } else {
+ mValues = newUnpaddedLongArray(initialCapacity);
+ }
+ mSize = 0;
+ mHead = mTail = 0;
+ }
+
+ /**
+ * Initializes a queue with default starting capacity.
+ */
+ public LongArrayQueue() {
+ this(16);
+ }
+
+ /** @hide */
+ public static int growSize(int currentSize) {
+ return currentSize <= 4 ? 8 : currentSize * 2;
+ }
+
+ private void grow() {
+ if (mSize < mValues.length) {
+ throw new IllegalStateException("Queue not full yet!");
+ }
+ final int newSize = growSize(mSize);
+ final long[] newArray = newUnpaddedLongArray(newSize);
+ final int r = mValues.length - mHead; // Number of elements on and to the right of head.
+ System.arraycopy(mValues, mHead, newArray, 0, r);
+ System.arraycopy(mValues, 0, newArray, r, mHead);
+ mValues = newArray;
+ mHead = 0;
+ mTail = mSize;
+ }
+
+ /**
+ * Returns the number of elements in the queue.
+ */
+ public int size() {
+ return mSize;
+ }
+
+ /**
+ * Removes all elements from this queue.
+ */
+ public void clear() {
+ mSize = 0;
+ mHead = mTail = 0;
+ }
+
+ /**
+ * Adds a value to the tail of the queue.
+ *
+ * @param value the value to be added.
+ */
+ public void addLast(long value) {
+ if (mSize == mValues.length) {
+ grow();
+ }
+ mValues[mTail] = value;
+ mTail = (mTail + 1) % mValues.length;
+ mSize++;
+ }
+
+ /**
+ * Removes an element from the head of the queue.
+ *
+ * @return the element at the head of the queue.
+ * @throws NoSuchElementException if the queue is empty.
+ */
+ public long removeFirst() {
+ if (mSize == 0) {
+ throw new NoSuchElementException("Queue is empty!");
+ }
+ final long ret = mValues[mHead];
+ mHead = (mHead + 1) % mValues.length;
+ mSize--;
+ return ret;
+ }
+
+ /**
+ * Returns the element at the given position from the head of the queue, where 0 represents the
+ * head of the queue.
+ *
+ * @param position the position from the head of the queue.
+ * @return the element found at the given position.
+ * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or
+ * {@code position} >= {@link #size()}
+ */
+ public long get(int position) {
+ if (position < 0 || position >= mSize) {
+ throw new IndexOutOfBoundsException("Index " + position
+ + " not valid for a queue of size " + mSize);
+ }
+ final int index = (mHead + position) % mValues.length;
+ return mValues[index];
+ }
+
+ /**
+ * Returns the element at the head of the queue, without removing it.
+ *
+ * @return the element at the head of the queue.
+ * @throws NoSuchElementException if the queue is empty
+ */
+ public long peekFirst() {
+ if (mSize == 0) {
+ throw new NoSuchElementException("Queue is empty!");
+ }
+ return mValues[mHead];
+ }
+
+ /**
+ * Returns the element at the tail of the queue.
+ *
+ * @return the element at the tail of the queue.
+ * @throws NoSuchElementException if the queue is empty.
+ */
+ public long peekLast() {
+ if (mSize == 0) {
+ throw new NoSuchElementException("Queue is empty!");
+ }
+ final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1;
+ return mValues[index];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ if (mSize <= 0) {
+ return "{}";
+ }
+
+ final StringBuilder buffer = new StringBuilder(mSize * 64);
+ buffer.append('{');
+ buffer.append(get(0));
+ for (int i = 1; i < mSize; i++) {
+ buffer.append(", ");
+ buffer.append(get(i));
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java b/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java
new file mode 100644
index 000000000000..dbbef61f6777
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java
@@ -0,0 +1,118 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import com.android.modules.utils.TypedXmlPullParser;
+
+import libcore.util.XmlObjectFactory;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Copied over partly from frameworks/base/core/java/com/android/internal/util/XmlUtils.java
+ *
+ * @hide
+ */
+public class XmlUtils {
+
+ private static final String STRING_ARRAY_SEPARATOR = ":";
+
+ /** @hide */
+ public static final void beginDocument(XmlPullParser parser, String firstElementName)
+ throws XmlPullParserException, IOException {
+ int type;
+ while ((type = parser.next()) != parser.START_TAG
+ && type != parser.END_DOCUMENT) {
+ // Do nothing
+ }
+
+ if (type != parser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ if (!parser.getName().equals(firstElementName)) {
+ throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
+ + ", expected " + firstElementName);
+ }
+ }
+
+ /** @hide */
+ public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
+ throws IOException, XmlPullParserException {
+ for (;;) {
+ int type = parser.next();
+ if (type == XmlPullParser.END_DOCUMENT
+ || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
+ return false;
+ }
+ if (type == XmlPullParser.START_TAG
+ && parser.getDepth() == outerDepth + 1) {
+ return true;
+ }
+ }
+ }
+
+ private static XmlPullParser newPullParser() {
+ try {
+ XmlPullParser parser = XmlObjectFactory.newXmlPullParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ return parser;
+ } catch (XmlPullParserException e) {
+ throw new AssertionError();
+ }
+ }
+
+ /** @hide */
+ public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
+ throws IOException {
+ final byte[] magic = new byte[4];
+ if (in instanceof FileInputStream) {
+ try {
+ Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ } else {
+ if (!in.markSupported()) {
+ in = new BufferedInputStream(in);
+ }
+ in.mark(8);
+ in.read(magic);
+ in.reset();
+ }
+
+ final TypedXmlPullParser xml;
+ xml = (TypedXmlPullParser) newPullParser();
+ try {
+ xml.setInput(in, "UTF_8");
+ } catch (XmlPullParserException e) {
+ throw new IOException(e);
+ }
+ return xml;
+ }
+}
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index f063074b39b4..c6fd92c6e9b7 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -127,10 +127,10 @@ private fun getCredentialOptionInfoList(
userName = credentialEntry.username.toString(),
displayName = credentialEntry.displayName?.toString(),
icon = credentialEntry.icon.loadDrawable(context),
- shouldTintIcon = credentialEntry.isDefaultIcon,
+ shouldTintIcon = credentialEntry.hasDefaultIcon,
lastUsedTimeMillis = credentialEntry.lastUsedTime,
isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
- credentialEntry.autoSelectAllowedFromOption,
+ credentialEntry.isAutoSelectAllowedFromOption,
)
)
}
@@ -148,10 +148,10 @@ private fun getCredentialOptionInfoList(
userName = credentialEntry.username.toString(),
displayName = credentialEntry.displayName?.toString(),
icon = credentialEntry.icon.loadDrawable(context),
- shouldTintIcon = credentialEntry.isDefaultIcon,
+ shouldTintIcon = credentialEntry.hasDefaultIcon,
lastUsedTimeMillis = credentialEntry.lastUsedTime,
isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
- credentialEntry.autoSelectAllowedFromOption,
+ credentialEntry.isAutoSelectAllowedFromOption,
)
)
}
@@ -170,10 +170,10 @@ private fun getCredentialOptionInfoList(
userName = credentialEntry.title.toString(),
displayName = credentialEntry.subtitle?.toString(),
icon = credentialEntry.icon.loadDrawable(context),
- shouldTintIcon = credentialEntry.isDefaultIcon,
+ shouldTintIcon = credentialEntry.hasDefaultIcon,
lastUsedTimeMillis = credentialEntry.lastUsedTime,
isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
- credentialEntry.autoSelectAllowedFromOption,
+ credentialEntry.isAutoSelectAllowedFromOption,
)
)
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
index fe1529d11cd8..9c518de18582 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
@@ -192,7 +192,7 @@ public class VolumeControlProfileTest {
mServiceListener.onServiceConnected(BluetoothProfile.VOLUME_CONTROL, mService);
final Executor executor = (command -> new Thread(command).start());
- final BluetoothVolumeControl.Callback callback = (device, volumeOffset) -> {};
+ final BluetoothVolumeControl.Callback callback = new BluetoothVolumeControl.Callback() {};
mProfile.registerCallback(executor, callback);
verify(mService).registerCallback(executor, callback);
@@ -200,7 +200,7 @@ public class VolumeControlProfileTest {
@Test
public void unregisterCallback_verifyIsCalled() {
- final BluetoothVolumeControl.Callback callback = (device, volumeOffset) -> {};
+ final BluetoothVolumeControl.Callback callback = new BluetoothVolumeControl.Callback() {};
mServiceListener.onServiceConnected(BluetoothProfile.VOLUME_CONTROL, mService);
mProfile.unregisterCallback(callback);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 62b8cb73af48..999507b300e4 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -214,6 +214,8 @@ android_library {
javacflags: [
"-Adagger.fastInit=enabled",
+ "-Adagger.explicitBindingConflictsWithInject=ERROR",
+ "-Adagger.strictMultibindingValidation=enabled",
"-Aroom.schemaLocation=frameworks/base/packages/SystemUI/schemas",
],
kotlincflags: ["-Xjvm-default=all"],
@@ -327,12 +329,13 @@ android_library {
"WindowManager-Shell",
"LowLightDreamLib",
"motion_tool_lib",
- "androidx.core_core-animation-testing-nodeps",
+ "androidx.core_core-animation-testing",
"androidx.compose.ui_ui",
"flag-junit",
"platform-test-annotations",
"notification_flags_lib",
],
+ skip_jarjar_repackage: true,
}
android_library {
@@ -382,6 +385,7 @@ android_library {
test: true,
extra_check_modules: ["SystemUILintChecker"],
},
+ skip_jarjar_repackage: true,
}
android_app {
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index b900ea0c0f65..e945f1eb0991 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -41,7 +41,7 @@ android_library {
],
static_libs: [
- "androidx.core_core-animation-nodeps",
+ "androidx.core_core-animation",
"androidx.core_core-ktx",
"androidx.annotation_annotation",
"SystemUIShaderLib",
@@ -62,7 +62,7 @@ android_library {
],
static_libs: [
- "androidx.core_core-animation-nodeps",
+ "androidx.core_core-animation",
"androidx.core_core-ktx",
"androidx.annotation_annotation",
],
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 3a33f92bf7d1..71e084ee547e 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -35,6 +35,9 @@ java_library {
srcs: [
":statslog-SystemUI-java-gen",
],
+ libs: [
+ "androidx.annotation_annotation",
+ ],
lint: {
baseline_filename: "lint-baseline.xml",
},
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 236c5b8ed2d7..cc5be8d0b47e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -59,6 +59,7 @@ import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyControllerImpl;
import com.android.systemui.statusbar.policy.SensorPrivacyController;
import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
+import com.android.systemui.unfold.UnfoldTransitionModule;
import com.android.systemui.volume.dagger.VolumeModule;
import com.android.systemui.wallpapers.dagger.WallpaperModule;
@@ -99,6 +100,7 @@ import javax.inject.Named;
RotationLockModule.class,
SceneContainerFrameworkModule.class,
StartCentralSurfacesModule.class,
+ UnfoldTransitionModule.Startables.class,
VolumeModule.class,
WallpaperModule.class,
KeyboardShortcutsModule.class
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index 10fc83c8b82c..8cbe9c5e56cf 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -26,7 +26,6 @@ import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager
import com.android.systemui.util.kotlin.getOrNull
import dagger.BindsInstance
-import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
@@ -34,7 +33,9 @@ import java.util.Optional
import javax.inject.Named
import javax.inject.Scope
-@Scope @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class SysUIUnfoldScope
+@Scope @MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class SysUIUnfoldScope
/**
* Creates an injectable [SysUIUnfoldComponent] that provides objects that have been scoped with
@@ -49,7 +50,6 @@ import javax.inject.Scope
*/
@Module(subcomponents = [SysUIUnfoldComponent::class])
class SysUIUnfoldModule {
-
@Provides
@SysUISingleton
fun provideSysUIUnfoldComponent(
@@ -57,8 +57,7 @@ class SysUIUnfoldModule {
rotationProvider: Optional<NaturalRotationUnfoldProgressProvider>,
@Named(UNFOLD_STATUS_BAR) scopedProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
@UnfoldBg bgProvider: Optional<UnfoldTransitionProgressProvider>,
- unfoldLatencyTracker: Lazy<UnfoldLatencyTracker>,
- factory: SysUIUnfoldComponent.Factory
+ factory: SysUIUnfoldComponent.Factory,
): Optional<SysUIUnfoldComponent> {
val p1 = provider.getOrNull()
val p2 = rotationProvider.getOrNull()
@@ -67,7 +66,7 @@ class SysUIUnfoldModule {
return if (p1 == null || p2 == null || p3 == null || p4 == null) {
Optional.empty()
} else {
- Optional.of(factory.create(p1, p2, p3, p4, unfoldLatencyTracker.get()))
+ Optional.of(factory.create(p1, p2, p3, p4))
}
}
}
@@ -75,7 +74,6 @@ class SysUIUnfoldModule {
@SysUIUnfoldScope
@Subcomponent
interface SysUIUnfoldComponent {
-
@Subcomponent.Factory
interface Factory {
fun create(
@@ -83,7 +81,6 @@ interface SysUIUnfoldComponent {
@BindsInstance p2: NaturalRotationUnfoldProgressProvider,
@BindsInstance p3: ScopedUnfoldTransitionProgressProvider,
@BindsInstance @UnfoldBg p4: UnfoldTransitionProgressProvider,
- @BindsInstance p5: UnfoldLatencyTracker,
): SysUIUnfoldComponent
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index 50515daedc51..3c55ce912072 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -170,14 +170,17 @@ class UnfoldTransitionModule {
@Module
interface Bindings {
+ @Binds fun bindRepository(impl: UnfoldTransitionRepositoryImpl): UnfoldTransitionRepository
+
+ @Binds fun bindInteractor(impl: UnfoldTransitionInteractorImpl): UnfoldTransitionInteractor
+ }
+
+ @Module
+ interface Startables {
@Binds
@IntoMap
@ClassKey(UnfoldTraceLogger::class)
fun bindUnfoldTraceLogger(impl: UnfoldTraceLogger): CoreStartable
-
- @Binds fun bindRepository(impl: UnfoldTransitionRepositoryImpl): UnfoldTransitionRepository
-
- @Binds fun bindInteractor(impl: UnfoldTransitionInteractorImpl): UnfoldTransitionInteractor
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java
index 206babf9ec44..09675e28f5da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java
@@ -23,6 +23,7 @@ import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
+import androidx.lifecycle.ViewModel;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -56,7 +57,8 @@ public class ComplicationViewModelTransformerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
when(mFactory.create(Mockito.any(), Mockito.any())).thenReturn(mComponent);
when(mComponent.getViewModelProvider()).thenReturn(mViewModelProvider);
- when(mViewModelProvider.get(Mockito.any(), Mockito.any())).thenReturn(mViewModel);
+ when(mViewModelProvider.get(Mockito.any(), Mockito.<Class<ViewModel>>any()))
+ .thenReturn(mViewModel);
}
/**
diff --git a/packages/Tethering/OWNERS b/packages/Tethering/OWNERS
deleted file mode 100644
index aa87958f1d53..000000000000
--- a/packages/Tethering/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/Android.bp b/services/Android.bp
index 5cb8ec628c38..474d501bca7a 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -219,6 +219,7 @@ java_library {
required: [
"libukey2_jni_shared",
+ "protolog.conf.json.gz",
],
// Uncomment to enable output of certain warnings (deprecated, unchecked)
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index 6e76a207e06f..0e35a409c82c 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,6 +1,13 @@
-pweaver@google.com
-sallyyuen@google.com
-ryanlwlin@google.com
-fuego@google.com
+# Bug component: 44215
+
+# Android Accessibility Framework owners
danielnorman@google.com
aarmaly@google.com
+chunkulin@google.com
+fuego@google.com
+sallyyuen@google.com
+
+# Android Accessibility members who have OWNERS but should not be sent
+# day-to-day changes for code review:
+pweaver@google.com #{LAST_RESORT_SUGGESTION}
+ryanlwlin@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index d9e25ef7dcdc..e13994e75690 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -525,8 +525,9 @@ public class TouchState {
mReceivedPointersDown |= pointerFlag;
mReceivedPointers[pointerId].set(
event.getX(pointerIndex), event.getY(pointerIndex), event.getEventTime());
-
- mPrimaryPointerId = pointerId;
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mPrimaryPointerId = pointerId;
+ }
}
/**
diff --git a/services/backup/BACKUP_OWNERS b/services/backup/BACKUP_OWNERS
index f8f4f4f4bf2e..29ae2027fc3a 100644
--- a/services/backup/BACKUP_OWNERS
+++ b/services/backup/BACKUP_OWNERS
@@ -2,9 +2,10 @@
jstemmer@google.com
martinoh@google.com
-millmore@google.com
niamhfw@google.com
piee@google.com
philippov@google.com
rthakohov@google.com
-sarpm@google.com \ No newline at end of file
+sarpm@google.com
+beatricemarch@google.com
+azilio@google.com \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2ee39c577977..09c1dea2f65a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19423,7 +19423,7 @@ public class ActivityManagerService extends IActivityManager.Stub
record.procStateSeqWaitingForNetwork = 0;
final long totalTime = SystemClock.uptimeMillis() - startTime;
if (totalTime >= mConstants.mNetworkAccessTimeoutMs || DEBUG_NETWORK) {
- Slog.w(TAG_NETWORK, "Total time waited for network rules to get updated: "
+ Slog.wtf(TAG_NETWORK, "Total time waited for network rules to get updated: "
+ totalTime + ". Uid: " + callingUid + " procStateSeq: "
+ procStateSeq + " UidRec: " + record
+ " validateUidRec: "
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
index 507fd9efaffd..826629924ab7 100644
--- a/services/core/java/com/android/server/am/LmkdStatsReporter.java
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -45,6 +45,7 @@ public final class LmkdStatsReporter {
private static final int LOW_MEM_AND_SWAP_UTIL = 6;
private static final int LOW_FILECACHE_AFTER_THRASHING = 7;
private static final int LOW_MEM = 8;
+ private static final int DIRECT_RECL_STUCK = 9;
/**
* Processes the LMK_KILL_OCCURRED packet data
@@ -109,6 +110,8 @@ public final class LmkdStatsReporter {
return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_FILECACHE_AFTER_THRASHING;
case LOW_MEM:
return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM;
+ case DIRECT_RECL_STUCK:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__DIRECT_RECL_STUCK;
default:
return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__UNKNOWN;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5a078dbfa7b8..0bfbee694366 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4595,6 +4595,7 @@ public class AudioService extends IAudioService.Stub
case AudioSystem.MODE_CALL_SCREENING:
case AudioSystem.MODE_CALL_REDIRECT:
case AudioSystem.MODE_COMMUNICATION_REDIRECT:
+ case AudioSystem.MODE_RINGTONE:
break;
default:
// no-op is enough for all other values
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index f9568ea9d72b..6eba23f45fdf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -256,10 +256,10 @@ public abstract class AuthenticationClient<T, O extends AuthenticateOptions>
// For BP, BiometricService will add the authToken to Keystore.
if (!isBiometricPrompt() && mIsStrongBiometric) {
final int result = KeyStore.getInstance().addAuthToken(byteToken);
- if (result != KeyStore.NO_ERROR) {
+ if (result != 0) {
Slog.d(TAG, "Error adding auth token : " + result);
} else {
- Slog.d(TAG, "addAuthToken: " + result);
+ Slog.d(TAG, "addAuthToken succeeded");
}
} else {
Slog.d(TAG, "Skipping addAuthToken");
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b7ece2ea65b1..5905b7de5b6e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -366,7 +366,6 @@ public class Vpn {
private PendingIntent mStatusIntent;
private volatile boolean mEnableTeardown = true;
- private final INetworkManagementService mNms;
private final INetd mNetd;
@VisibleForTesting
@GuardedBy("this")
@@ -626,7 +625,6 @@ public class Vpn {
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
mDeps = deps;
- mNms = netService;
mNetd = netd;
mUserId = userId;
mLooper = looper;
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java b/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java
new file mode 100644
index 000000000000..133c79f81bb5
--- /dev/null
+++ b/services/core/java/com/android/server/crashrecovery/CrashRecoveryHelper.java
@@ -0,0 +1,129 @@
+/*
+ * 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 com.android.server.crashrecovery;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.net.ConnectivityModuleConnector;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.server.PackageWatchdog;
+import com.android.server.pm.ApexManager;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Provides helper methods for the CrashRecovery APEX
+ *
+ * @hide
+ */
+public final class CrashRecoveryHelper {
+ private static final String TAG = "CrashRecoveryHelper";
+
+ private final ApexManager mApexManager;
+ private final Context mContext;
+ private final ConnectivityModuleConnector mConnectivityModuleConnector;
+
+
+ /** @hide */
+ public CrashRecoveryHelper(@NonNull Context context) {
+ mContext = context;
+ mApexManager = ApexManager.getInstance();
+ mConnectivityModuleConnector = ConnectivityModuleConnector.getInstance();
+ }
+
+ /**
+ * Returns true if the package name is the name of a module.
+ * If the package is an APK inside an APEX then it will use the parent's APEX package name
+ * do determine if it is a module or not.
+ * @hide
+ */
+ @AnyThread
+ public boolean isModule(@NonNull String packageName) {
+ String apexPackageName =
+ mApexManager.getActiveApexPackageNameContainingPackage(packageName);
+ if (apexPackageName != null) {
+ packageName = apexPackageName;
+ }
+
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ return pm.getModuleInfo(packageName, 0) != null;
+ } catch (PackageManager.NameNotFoundException ignore) {
+ return false;
+ }
+ }
+
+ /**
+ * Register health listeners for explicit package failures.
+ * Currently only registering for Connectivity Module health.
+ * @hide
+ */
+ public void registerConnectivityModuleHealthListener(@NonNull int failureReason) {
+ // register listener for ConnectivityModule
+ mConnectivityModuleConnector.registerHealthListener(
+ packageName -> {
+ final VersionedPackage pkg = getVersionedPackage(packageName);
+ if (pkg == null) {
+ Slog.wtf(TAG, "NetworkStack failed but could not find its package");
+ return;
+ }
+ final List<VersionedPackage> pkgList = Collections.singletonList(pkg);
+ PackageWatchdog.getInstance(mContext).onPackageFailure(pkgList, failureReason);
+ });
+ }
+
+ @Nullable
+ private VersionedPackage getVersionedPackage(String packageName) {
+ final PackageManager pm = mContext.getPackageManager();
+ if (pm == null || TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+ try {
+ final long versionCode = getPackageInfo(packageName).getLongVersionCode();
+ return new VersionedPackage(packageName, versionCode);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets PackageInfo for the given package. Matches any user and apex.
+ *
+ * @throws PackageManager.NameNotFoundException if no such package is installed.
+ */
+ private PackageInfo getPackageInfo(String packageName)
+ throws PackageManager.NameNotFoundException {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ // The MATCH_ANY_USER flag doesn't mix well with the MATCH_APEX
+ // flag, so make two separate attempts to get the package info.
+ // We don't need both flags at the same time because we assume
+ // apex files are always installed for all users.
+ return pm.getPackageInfo(packageName, PackageManager.MATCH_ANY_USER);
+ } catch (PackageManager.NameNotFoundException e) {
+ return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/crashrecovery/OWNERS b/services/core/java/com/android/server/crashrecovery/OWNERS
new file mode 100644
index 000000000000..daa02111f71f
--- /dev/null
+++ b/services/core/java/com/android/server/crashrecovery/OWNERS
@@ -0,0 +1,3 @@
+ancr@google.com
+harshitmahajan@google.com
+robertogil@google.com
diff --git a/services/core/java/com/android/server/inputmethod/LocaleUtils.java b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
index 7d090dbcc5d8..b1348b3c785f 100644
--- a/services/core/java/com/android/server/inputmethod/LocaleUtils.java
+++ b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
@@ -46,29 +46,44 @@ final class LocaleUtils {
* @param desired The locale preferred by user.
* @return A score based on the locale matching for the default subtype enabling.
*/
- @IntRange(from = 1, to = 3)
+ @IntRange(from = 1, to = 4)
private static byte calculateMatchingSubScore(@NonNull final ULocale supported,
@NonNull final ULocale desired) {
// Assuming supported/desired is fully expanded.
if (supported.equals(desired)) {
- return 3; // Exact match.
+ return 4; // Exact match.
}
+ // addLikelySubtags is a maximization process as per
+ // https://www.unicode.org/reports/tr35/#Likely_Subtags
+ ULocale maxDesired = ULocale.addLikelySubtags(desired);
+
// Skip language matching since it was already done in calculateMatchingScore.
final String supportedScript = supported.getScript();
- if (supportedScript.isEmpty() || !supportedScript.equals(desired.getScript())) {
+ if (supportedScript.isEmpty() || !supportedScript.equals(maxDesired.getScript())) {
// TODO: Need subscript matching. For example, Hanb should match with Bopo.
return 1;
}
final String supportedCountry = supported.getCountry();
- if (supportedCountry.isEmpty() || !supportedCountry.equals(desired.getCountry())) {
+ if (supportedCountry.isEmpty() || !supportedCountry.equals(maxDesired.getCountry())) {
return 2;
}
// Ignore others e.g. variants, extensions.
- return 3;
+
+ // Since addLikelySubtags can canonicalize subtags, e.g. the deprecated country codes
+ // an locale with an identical script and country before addLikelySubtags is in favour,
+ // and a score of 4 is returned.
+ String desiredScript = desired.getScript();
+ String desiredCountry = desired.getCountry();
+ if ((desiredScript.isEmpty() || desiredScript.equals(maxDesired.getScript()))
+ && (desiredCountry.isEmpty() || desiredCountry.equals(maxDesired.getCountry()))) {
+ return 4;
+ } else {
+ return 3;
+ }
}
private static final class ScoreEntry implements Comparable<ScoreEntry> {
@@ -180,8 +195,7 @@ final class LocaleUtils {
ULocale.forLocale(preferredLocale));
}
score[j] = calculateMatchingSubScore(
- preferredULocaleCache[j],
- ULocale.addLikelySubtags(ULocale.forLocale(locale)));
+ preferredULocaleCache[j], ULocale.forLocale(locale));
if (canSkip && score[j] != 0) {
canSkip = false;
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2128cd14d65c..c6fca9b76f8e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -340,8 +340,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
static final String TAG = NetworkPolicyLogger.TAG;
private static final boolean LOGD = NetworkPolicyLogger.LOGD;
private static final boolean LOGV = NetworkPolicyLogger.LOGV;
- // TODO: b/304347838 - Remove once the feature is in staging.
- private static final boolean ALWAYS_RESTRICT_BACKGROUND_NETWORK = false;
/**
* No opportunistic quota could be calculated from user data plan or data settings.
@@ -1070,8 +1068,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
// The flag is boot-stable.
- mBackgroundNetworkRestricted = ALWAYS_RESTRICT_BACKGROUND_NETWORK
- && Flags.networkBlockedForTopSleepingAndAbove();
+ mBackgroundNetworkRestricted = Flags.networkBlockedForTopSleepingAndAbove();
if (mBackgroundNetworkRestricted) {
// Firewall rules and UidBlockedState will get updated in
// updateRulesForGlobalChangeAL below.
@@ -1217,16 +1214,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return false;
}
final int previousProcState = previousInfo.procState;
- if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE)
- != (newProcState >= BACKGROUND_THRESHOLD_STATE)) {
- // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the
- // BACKGROUND chain may change.
- return true;
- }
if ((previousProcState <= TOP_THRESHOLD_STATE)
- != (newProcState <= TOP_THRESHOLD_STATE)) {
- // Proc-state change crossed TOP_THRESHOLD_STATE: Network rules for the
- // LOW_POWER_STANDBY chain may change.
+ || (newProcState <= TOP_THRESHOLD_STATE)) {
+ // If the proc-state change crossed TOP_THRESHOLD_STATE, network rules for the
+ // LOW_POWER_STANDBY chain may change, so we need to evaluate the transition.
+ // In addition, we always process changes when the new process state is
+ // TOP_THRESHOLD_STATE or below, to avoid situations where the TOP app ends up
+ // waiting for NPMS to finish processing newProcStateSeq, even when it was
+ // redundant (b/327303931).
return true;
}
if ((previousProcState <= FOREGROUND_THRESHOLD_STATE)
@@ -1235,6 +1230,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// different chains may change.
return true;
}
+ if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE)
+ != (newProcState >= BACKGROUND_THRESHOLD_STATE)) {
+ // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the
+ // BACKGROUND chain may change.
+ return true;
+ }
final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
| PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
if ((previousInfo.capability & networkCapabilities)
@@ -4325,7 +4326,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
private boolean updateUidStateUL(int uid, int procState, long procStateSeq,
@ProcessCapability int capability) {
- Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL: " + uid + "/"
+ + ActivityManager.procStateToString(procState) + "/" + procStateSeq + "/"
+ + ActivityManager.getCapabilitiesSummary(capability));
try {
final UidState oldUidState = mUidState.get(uid);
if (oldUidState != null && procStateSeq < oldUidState.procStateSeq) {
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index d0e95dd55b6c..669cdaaf3ab5 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -4,3 +4,4 @@ file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
jsharkey@android.com
sudheersai@google.com
yamasani@google.com
+suprabh@google.com
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 600aff290193..a5c323ab287c 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -112,7 +112,6 @@ import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.ArchivedPackageParcel;
import android.content.pm.DataLoaderType;
-import android.content.pm.Flags;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
@@ -2556,9 +2555,7 @@ final class InstallPackageHelper {
& PackageManager.INSTALL_IGNORE_DEXOPT_PROFILE)
!= 0;
/*@DexoptFlags*/ int extraFlags =
- ignoreDexoptProfile && Flags.useArtServiceV2()
- ? ArtFlags.FLAG_IGNORE_PROFILE
- : 0;
+ ignoreDexoptProfile ? ArtFlags.FLAG_IGNORE_PROFILE : 0;
DexoptParams params = dexoptOptions.convertToDexoptParams(extraFlags);
DexoptResult dexOptResult = DexOptHelper.getArtManagerLocal().dexoptPackage(
snapshot, packageName, params);
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index ee780d99b6b6..dcb9f1aad814 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -35,7 +35,6 @@ import android.apex.ApexInfo;
import android.app.AppOpsManager;
import android.content.pm.ArchivedPackageParcel;
import android.content.pm.DataLoaderType;
-import android.content.pm.Flags;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -931,7 +930,7 @@ final class InstallRequest {
// Only report external profile warnings when installing from adb. The goal is to warn app
// developers if they have provided bad external profiles, so it's not beneficial to report
// those warnings in the normal app install workflow.
- if (isInstallFromAdb() && Flags.useArtServiceV2()) {
+ if (isInstallFromAdb()) {
var externalProfileErrors = new LinkedHashSet<String>();
for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) {
for (DexContainerFileDexoptResult fileResult :
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 35861d79875d..7877d5d6ec2f 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -153,7 +153,8 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_CELLULAR_2G,
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
UserManager.DISALLOW_CONFIG_DEFAULT_APPS,
- UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO
+ UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
+ UserManager.DISALLOW_THREAD_NETWORK
});
public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet(
@@ -204,7 +205,8 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_ADD_WIFI_CONFIG,
UserManager.DISALLOW_CELLULAR_2G,
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
- UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO
+ UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
+ UserManager.DISALLOW_THREAD_NETWORK
);
/**
@@ -248,7 +250,8 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_ADD_WIFI_CONFIG,
UserManager.DISALLOW_CELLULAR_2G,
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
- UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO
+ UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
+ UserManager.DISALLOW_THREAD_NETWORK
);
/**
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ec5172fca5fa..969784bcc4e7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3933,7 +3933,7 @@ public final class PowerManagerService extends SystemService
UserspaceRebootLogger.noteUserspaceRebootWasRequested();
}
if (mHandler == null || !mSystemReady) {
- if (RescueParty.isAttemptingFactoryReset()) {
+ if (RescueParty.isRecoveryTriggeredReboot()) {
// If we're stuck in a really low-level reboot loop, and a
// rescue party is trying to prompt the user for a factory data
// reset, we must GET TO DA CHOPPA!
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 871e98bf4ab3..8ae515401c60 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -332,7 +332,7 @@ public final class ShutdownThread extends Thread {
com.android.internal.R.string.reboot_to_update_reboot));
}
} else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
- if (RescueParty.isAttemptingFactoryReset()) {
+ if (RescueParty.isRecoveryTriggeredReboot()) {
// We're not actually doing a factory reset yet; we're rebooting
// to ask the user if they'd like to reset, so give them a less
// scary dialog message.
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 698f6ea4b443..4eea8c62822e 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -3708,6 +3708,7 @@ public class BatteryStatsImpl extends BatteryStats {
public abstract T instantiateObject();
}
+ @SuppressWarnings("ParcelableCreator")
public static class ControllerActivityCounterImpl extends ControllerActivityCounter
implements Parcelable {
private final Clock mClock;
diff --git a/services/core/java/com/android/server/rollback/OWNERS b/services/core/java/com/android/server/rollback/OWNERS
index daa02111f71f..8337fd2453df 100644
--- a/services/core/java/com/android/server/rollback/OWNERS
+++ b/services/core/java/com/android/server/rollback/OWNERS
@@ -1,3 +1 @@
-ancr@google.com
-harshitmahajan@google.com
-robertogil@google.com
+include /services/core/java/com/android/server/crashrecovery/OWNERS \ No newline at end of file
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 099c9ae33bfb..17f5e9585c22 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -44,6 +44,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
@@ -318,8 +319,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
if (SubscriptionManager.isValidSubscriptionId(subId)) {
// Get only configs as needed to save memory.
- final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId,
- VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
+ final PersistableBundle carrierConfig =
+ Flags.fixCrashOnGettingConfigWhenPhoneIsGone()
+ ? CarrierConfigManager.getCarrierConfigSubset(mContext, subId,
+ VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS)
+ : mCarrierConfigManager.getConfigForSubId(subId,
+ VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) {
mReadySubIdsBySlotId.put(slotId, subId);
diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
index a25d67ab66af..ed9fa65dee15 100644
--- a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
+++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
@@ -24,8 +24,10 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.ConnectivityManager;
import android.net.IpSecTransformState;
import android.net.Network;
+import android.net.vcn.Flags;
import android.net.vcn.VcnManager;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -71,6 +73,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
@NonNull private final Handler mHandler;
@NonNull private final PowerManager mPowerManager;
+ @NonNull private final ConnectivityManager mConnectivityManager;
@NonNull private final Object mCancellationToken = new Object();
@NonNull private final PacketLossCalculator mPacketLossCalculator;
@@ -98,6 +101,8 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
mHandler = new Handler(getVcnContext().getLooper());
mPowerManager = getVcnContext().getContext().getSystemService(PowerManager.class);
+ mConnectivityManager =
+ getVcnContext().getContext().getSystemService(ConnectivityManager.class);
mPacketLossCalculator = deps.getPacketLossCalculator();
@@ -205,6 +210,18 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
}
@Override
+ public void onLinkPropertiesOrCapabilitiesChanged() {
+ if (!isStarted()) return;
+
+ reschedulePolling();
+ }
+
+ private void reschedulePolling() {
+ mHandler.removeCallbacksAndEqualMessages(mCancellationToken);
+ mHandler.postDelayed(new PollIpSecStateRunnable(), mCancellationToken, 0L);
+ }
+
+ @Override
protected void start() {
super.start();
clearTransformStateAndPollingEvents();
@@ -313,6 +330,13 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
} else {
logInfo(logMsg);
onValidationResultReceivedInternal(true /* isFailed */);
+
+ if (Flags.validateNetworkOnIpsecLoss()) {
+ // Trigger re-validation of the underlying network; if it fails, the VCN will
+ // attempt to migrate away.
+ mConnectivityManager.reportNetworkConnectivity(
+ getNetwork(), false /* hasConnectivity */);
+ }
}
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
index 1704aa117a2b..a1b212f8d3d7 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
@@ -186,6 +186,11 @@ public abstract class NetworkMetricMonitor implements AutoCloseable {
// Subclasses MUST override it if they care
}
+ /** Called when LinkProperties or NetworkCapabilities have changed */
+ public void onLinkPropertiesOrCapabilitiesChanged() {
+ // Subclasses MUST override it if they care
+ }
+
public boolean isValidationFailed() {
return mIsValidationFailed;
}
@@ -203,6 +208,11 @@ public abstract class NetworkMetricMonitor implements AutoCloseable {
return mVcnContext;
}
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
// Override methods for AutoCloseable. Subclasses MUST call super when overriding this method
@Override
public void close() {
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
index 2f4cf5e5d8c7..78e06d46c74c 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
@@ -25,6 +25,7 @@ import android.net.IpSecTransform;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.vcn.Flags;
import android.net.vcn.VcnManager;
import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.os.Handler;
@@ -295,6 +296,12 @@ public class UnderlyingNetworkEvaluator {
updatePriorityClass(
underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig);
+
+ if (Flags.evaluateIpsecLossOnLpNcChange()) {
+ for (NetworkMetricMonitor monitor : mMetricMonitors) {
+ monitor.onLinkPropertiesOrCapabilitiesChanged();
+ }
+ }
}
/** Set the LinkProperties */
@@ -308,6 +315,12 @@ public class UnderlyingNetworkEvaluator {
updatePriorityClass(
underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig);
+
+ if (Flags.evaluateIpsecLossOnLpNcChange()) {
+ for (NetworkMetricMonitor monitor : mMetricMonitors) {
+ monitor.onLinkPropertiesOrCapabilitiesChanged();
+ }
+ }
}
/** Set whether the network is blocked */
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index e06f2158dc14..79eb0dc620a5 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -24,3 +24,5 @@ per-file Background*Start* = set noparent
per-file Background*Start* = file:/BAL_OWNERS
per-file Background*Start* = ogunwale@google.com, louischang@google.com
+# File related to activity callers
+per-file ActivityCallerState.java = file:/core/java/android/app/COMPONENT_CALLER_OWNERS
diff --git a/services/core/jni/com_android_server_am_OomConnection.cpp b/services/core/jni/com_android_server_am_OomConnection.cpp
index 49a3ad35649b..054937fc683e 100644
--- a/services/core/jni/com_android_server_am_OomConnection.cpp
+++ b/services/core/jni/com_android_server_am_OomConnection.cpp
@@ -44,6 +44,12 @@ static MemEventListener memevent_listener(MemEventClient::AMS);
* @throws java.lang.RuntimeException
*/
static jobjectArray android_server_am_OomConnection_waitOom(JNIEnv* env, jobject) {
+ if (!memevent_listener.ok()) {
+ memevent_listener.deregisterAllEvents();
+ jniThrowRuntimeException(env, "Failed to initialize memevents listener");
+ return nullptr;
+ }
+
if (!memevent_listener.registerEvent(MEM_EVENT_OOM_KILL)) {
memevent_listener.deregisterAllEvents();
jniThrowRuntimeException(env, "listener failed to register to OOM events");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 0fc8c5e7a46a..260264d0fb9c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -475,6 +475,10 @@ final class PolicyDefinition<V> {
UserManager.DISALLOW_CELLULAR_2G, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ if (com.android.net.thread.platform.flags.Flags.threadUserRestrictionEnabled()) {
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_THREAD_NETWORK, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ }
for (String key : USER_RESTRICTION_FLAGS.keySet()) {
createAndAddUserRestrictionPolicyDefinition(key, USER_RESTRICTION_FLAGS.get(key));
diff --git a/services/proguard.flags b/services/proguard.flags
index 88561b460b05..a01e7dc16147 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -54,7 +54,10 @@
-keep,allowoptimization,allowaccessmodification class android.app.admin.flags.FeatureFlagsImpl { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.input.NativeInputManagerService$NativeImpl { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.ThreadPriorityBooster { *; }
--keep,allowaccessmodification class android.app.admin.flags.Flags { *; }
+
+# Keep all aconfig Flag class as they might be statically referenced by other packages
+# An merge or inlining could lead to missing dependencies that cause run time errors
+-keepclassmembernames class android.**.Flags, com.android.**.Flags { public *; }
# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing)
-keep public class com.android.server.utils.Slogf { *; }
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index 8d2541dca2df..dd3a4ca5a53c 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -94,7 +94,7 @@ android_test {
"libutils",
"netd_aidl_interface-V5-cpp",
],
-
+ compile_multilib: "both",
dxflags: ["--multi-dex"],
java_resources: [
diff --git a/services/tests/VpnTests/Android.bp b/services/tests/VpnTests/Android.bp
index 64a9a3b4f119..a5011a8d8b00 100644
--- a/services/tests/VpnTests/Android.bp
+++ b/services/tests/VpnTests/Android.bp
@@ -17,8 +17,7 @@ android_test {
"java/**/*.java",
"java/**/*.kt",
],
-
- defaults: ["framework-connectivity-test-defaults"],
+ sdk_version: "core_platform", // tests can use @CorePlatformApi's
test_suites: ["device-tests"],
static_libs: [
"androidx.test.rules",
@@ -32,6 +31,13 @@ android_test {
"service-connectivity-tiramisu-pre-jarjar",
],
libs: [
+ // order matters: classes in framework-connectivity are resolved before framework,
+ // meaning @hide APIs in framework-connectivity are resolved before @SystemApi
+ // stubs in framework
+ "framework-connectivity.impl",
+ "framework-connectivity-t.impl",
+ "framework",
+ "framework-res",
"android.test.runner",
"android.test.base",
"android.test.mock",
diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
index 9115f952b724..08155c7b3f98 100644
--- a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
+++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
@@ -3158,13 +3158,6 @@ public class VpnTest extends VpnTestBase {
assertEquals(profile, ikev2VpnProfile.toVpnProfile());
}
- private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
- assertNotNull(nc);
- VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
- assertNotNull(ti);
- assertEquals(type, ti.getType());
- }
-
// Make it public and un-final so as to spy it
public class TestDeps extends Vpn.Dependencies {
TestDeps() {}
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 211a83d8588e..682569f1d9ab 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -26,6 +26,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
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.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;
@@ -41,9 +42,11 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
import android.os.RecoverySystem;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.ArraySet;
@@ -55,6 +58,7 @@ import com.android.server.am.SettingsToPropertiesMapper;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
@@ -69,6 +73,7 @@ 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;
@@ -100,6 +105,9 @@ public class RescuePartyTest {
private static final int THROTTLING_DURATION_MIN = 10;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
private HashMap<String, String> mCrashRecoveryPropertiesMap;
@@ -267,6 +275,42 @@ public class RescuePartyTest {
}
@Test
+ public void testBootLoopDetectionWithExecutionForAllRescueLevelsRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+ any(Executor.class),
+ mMonitorCallbackCaptor.capture()));
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+
+ // Record DeviceConfig accesses
+ DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+
+ 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);
+ verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+
+ noteBoot(5);
+ verifyOnlySettingsReset(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteBoot(6);
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
noteAppCrash(1, true);
@@ -292,6 +336,47 @@ public class RescuePartyTest {
}
@Test
+ public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevelsRecoverability() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+ any(Executor.class),
+ mMonitorCallbackCaptor.capture()));
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+
+ // Record DeviceConfig accesses
+ DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.onDeviceConfigAccess(PERSISTENT_PACKAGE, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+
+ final String[] expectedResetNamespaces = new String[]{NAMESPACE1};
+ 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());
+
+ noteAppCrash(4, true);
+ verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+
+ noteAppCrash(5, true);
+ verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+
+ noteAppCrash(6, true);
+ verifyOnlySettingsReset(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteAppCrash(7, true);
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testNonPersistentAppOnlyPerformsFlagResets() {
noteAppCrash(1, false);
@@ -316,6 +401,45 @@ public class RescuePartyTest {
}
@Test
+ public void testNonPersistentAppOnlyPerformsFlagResetsRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+ any(Executor.class),
+ mMonitorCallbackCaptor.capture()));
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+
+ // Record DeviceConfig accesses
+ DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.onDeviceConfigAccess(NON_PERSISTENT_PACKAGE, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+
+ final String[] expectedResetNamespaces = new String[]{NAMESPACE1};
+ 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());
+
+ noteAppCrash(4, false);
+ verifyNoSettingsReset(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ noteAppCrash(5, false);
+ verifyNoSettingsReset(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+ noteAppCrash(6, false);
+ verifyNoSettingsReset(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteAppCrash(7, false);
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testNonPersistentAppCrashDetectionWithScopedResets() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -439,19 +563,32 @@ public class RescuePartyTest {
}
@Test
- public void testIsAttemptingFactoryReset() {
+ public void testIsRecoveryTriggeredReboot() {
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot(i + 1);
}
assertFalse(RescueParty.isFactoryResetPropertySet());
setCrashRecoveryPropAttemptingReboot(false);
noteBoot(LEVEL_FACTORY_RESET + 1);
- assertTrue(RescueParty.isAttemptingFactoryReset());
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @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 testIsAttemptingFactoryResetOnlyAfterRebootCompleted() {
+ public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompleted() {
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot(i + 1);
}
@@ -464,7 +601,26 @@ public class RescuePartyTest {
noteBoot(mitigationCount++);
setCrashRecoveryPropAttemptingReboot(false);
noteBoot(mitigationCount + 1);
- assertTrue(RescueParty.isAttemptingFactoryReset());
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @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());
}
@@ -477,7 +633,20 @@ public class RescuePartyTest {
for (int i = 1; i <= LEVEL_FACTORY_RESET; i++) {
noteBoot(i);
}
- assertFalse(RescueParty.isAttemptingFactoryReset());
+ assertFalse(RescueParty.isRecoveryTriggeredReboot());
+ }
+
+ @Test
+ public void testThrottlingOnBootFailuresRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ setCrashRecoveryPropAttemptingReboot(false);
+ long now = System.currentTimeMillis();
+ long beforeTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN - 1);
+ setCrashRecoveryPropLastFactoryReset(beforeTimeout);
+ for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteBoot(i);
+ }
+ assertFalse(RescueParty.isRecoveryTriggeredReboot());
}
@Test
@@ -489,7 +658,20 @@ public class RescuePartyTest {
for (int i = 0; i <= LEVEL_FACTORY_RESET; i++) {
noteAppCrash(i + 1, true);
}
- assertFalse(RescueParty.isAttemptingFactoryReset());
+ assertFalse(RescueParty.isRecoveryTriggeredReboot());
+ }
+
+ @Test
+ public void testThrottlingOnAppCrashRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ setCrashRecoveryPropAttemptingReboot(false);
+ long now = System.currentTimeMillis();
+ long beforeTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN - 1);
+ setCrashRecoveryPropLastFactoryReset(beforeTimeout);
+ for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteAppCrash(i + 1, true);
+ }
+ assertFalse(RescueParty.isRecoveryTriggeredReboot());
}
@Test
@@ -501,8 +683,22 @@ public class RescuePartyTest {
for (int i = 1; i <= LEVEL_FACTORY_RESET; i++) {
noteBoot(i);
}
- assertTrue(RescueParty.isAttemptingFactoryReset());
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
+ }
+
+ @Test
+ public void testNotThrottlingAfterTimeoutOnBootFailuresRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ setCrashRecoveryPropAttemptingReboot(false);
+ long now = System.currentTimeMillis();
+ long afterTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_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);
@@ -512,7 +708,20 @@ public class RescuePartyTest {
for (int i = 0; i <= LEVEL_FACTORY_RESET; i++) {
noteAppCrash(i + 1, true);
}
- assertTrue(RescueParty.isAttemptingFactoryReset());
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
+ }
+
+ @Test
+ public void testNotThrottlingAfterTimeoutOnAppCrashRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ setCrashRecoveryPropAttemptingReboot(false);
+ long now = System.currentTimeMillis();
+ long afterTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN + 1);
+ setCrashRecoveryPropLastFactoryReset(afterTimeout);
+ for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteAppCrash(i + 1, true);
+ }
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
}
@Test
@@ -531,6 +740,7 @@ 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,
@@ -543,6 +753,7 @@ 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));
@@ -568,6 +779,20 @@ 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
public void testHealthCheckLevels() {
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
@@ -594,6 +819,46 @@ public class RescuePartyTest {
}
@Test
+ 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
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_UNKNOWN, 1),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
+
+ // Ensure the correct user impact is returned for each mitigation count.
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 6),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 7),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+ }
+
+ @Test
public void testBootLoopLevels() {
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
@@ -606,6 +871,19 @@ public class RescuePartyTest {
}
@Test
+ 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(2), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+ assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_LEVEL_71);
+ assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_LEVEL_75);
+ assertEquals(observer.onBootLoop(5), PackageHealthObserverImpact.USER_IMPACT_LEVEL_80);
+ assertEquals(observer.onBootLoop(6), PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
+ }
+
+ @Test
public void testResetDeviceConfigForPackagesOnlyRuntimeMap() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -727,11 +1005,26 @@ public class RescuePartyTest {
private void verifySettingsResets(int resetMode, String[] resetNamespaces,
HashMap<String, Integer> configResetVerifiedTimesMap) {
+ verifyOnlySettingsReset(resetMode);
+ verifyDeviceConfigReset(resetNamespaces, configResetVerifiedTimesMap);
+ }
+
+ private void verifyOnlySettingsReset(int resetMode) {
verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
resetMode, UserHandle.USER_SYSTEM));
verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
eq(resetMode), anyInt()));
- // Verify DeviceConfig resets
+ }
+
+ private void verifyNoSettingsReset(int resetMode) {
+ verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
+ resetMode, UserHandle.USER_SYSTEM), never());
+ verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
+ eq(resetMode), anyInt()), never());
+ }
+
+ private void verifyDeviceConfigReset(String[] resetNamespaces,
+ Map<String, Integer> configResetVerifiedTimesMap) {
if (resetNamespaces == null) {
verify(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()), never());
} else {
@@ -818,9 +1111,16 @@ public class RescuePartyTest {
// mock properties in BootThreshold
try {
- mSpyBootThreshold = spy(watchdog.new BootThreshold(
- PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
- PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+ if (Flags.recoverabilityDetection()) {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+ } else {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+ }
mCrashRecoveryPropertiesMap = new HashMap<>();
doAnswer((Answer<Integer>) invocationOnMock -> {
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/OWNERS b/services/tests/mockingservicestests/src/com/android/server/rollback/OWNERS
index daa02111f71f..8337fd2453df 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/OWNERS
@@ -1,3 +1 @@
-ancr@google.com
-harshitmahajan@google.com
-robertogil@google.com
+include /services/core/java/com/android/server/crashrecovery/OWNERS \ No newline at end of file
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index fad8115be7e3..c333eb7eed46 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -255,3 +255,89 @@ java_genrule {
"done && " +
"$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
}
+
+FLAKY_AND_IGNORED = [
+ "androidx.test.filters.FlakyTest",
+ "org.junit.Ignore",
+]
+// Used by content protection TEST_MAPPING
+test_module_config {
+ name: "FrameworksServicesTests_contentprotection",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_filters: ["com.android.server.contentprotection"],
+ exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_om",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_filters: ["com.android.server.om."],
+ exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+// Used by contexthub TEST_MAPPING
+test_module_config {
+ name: "FrameworksServicesTests_contexthub_presubmit",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_filters: ["com.android.server.location.contexthub."],
+ // TODO(ron): are these right, does it run anything?
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+ exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_contexthub_postsubmit",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_filters: ["com.android.server.location.contexthub."],
+ // TODO(ron): are these right, does it run anything?
+ include_annotations: ["android.platform.test.annotations.Postsubmit"],
+ exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+// Used by contentcapture
+test_module_config {
+ name: "FrameworksServicesTests_contentcapture",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_filters: ["com.android.server.contentcapture"],
+ exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_recoverysystem",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_filters: ["com.android.server.recoverysystem."],
+ exclude_annotations: ["androidx.test.filters.FlakyTest"],
+}
+
+// server pm TEST_MAPPING
+test_module_config {
+ name: "FrameworksServicesTests_pm_presubmit",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+ include_filters: ["com.android.server.pm."],
+ exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_pm_postsubmit",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_annotations: ["android.platform.test.annotations.Postsubmit"],
+ include_filters: ["com.android.server.pm."],
+ exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+// server os TEST_MAPPING
+test_module_config {
+ name: "FrameworksServicesTests_os",
+ base: "FrameworksServicesTests",
+ test_suites: ["general-tests"],
+ include_filters: ["com.android.server.os."],
+}
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
index 0ffa891ce3e1..dae8f932cb91 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
@@ -14,5 +14,11 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ // b/331020193, Move to presubmit early april 2024
+ "name": "FrameworksServicesTests_contentcapture"
+ }
]
}
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
index 419508ca5e17..32729a899a96 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
@@ -14,5 +14,11 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ // b/331020193, Move to presubmit early april 2024
+ "name": "FrameworksServicesTests_contentprotection"
+ }
]
}
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
index 255cb6499d8a..26a2bee8cf68 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
@@ -357,6 +357,29 @@ public class LocaleUtilsTest {
assertEquals(1, dest.size());
assertEquals(availableLocales.get(0), dest.get(0)); // "sr-Latn-RS"
}
+ // Locale with deprecated subtag, e.g. CS for Serbia and Montenegro, should not win
+ // even if the other available locale doesn't have explicit script / country.
+ // On Android, users don't normally use deprecated subtags unless the application requests.
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-RS");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-CS"));
+ availableLocales.add(Locale.forLanguageTag("sr-RS"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "sr-RS"
+ }
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-RS");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-CS"));
+ availableLocales.add(Locale.forLanguageTag("sr"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "sr"
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
index 6035250500ec..dc8f934ff9e5 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
@@ -20,12 +20,18 @@
],
"postsubmit": [
{
+ // b/331020193, Move to presubmit early april 2024
+ "name": "FrameworksServicesTests_contexthub_presubmit"
+ },
+ {
"name": "FrameworksServicesTests",
"options": [
{
"include-filter": "com.android.server.location.contexthub."
},
{
+ // I believe this include annotation is preventing tests from being run
+ // as there are no matching tests with the Postsubmit annotation.
"include-annotation": "android.platform.test.annotations.Postsubmit"
},
{
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index ff19362061b6..bd30ef583903 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -206,7 +206,6 @@ import libcore.io.Streams;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
@@ -2151,14 +2150,12 @@ public class NetworkPolicyManagerServiceTest {
assertFalse(mService.isUidNetworkingBlocked(UID_E, false));
}
- @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainEnabled() throws Exception {
verify(mNetworkManager).setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true);
}
- @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainOnProcStateChange() throws Exception {
@@ -2188,7 +2185,6 @@ public class NetworkPolicyManagerServiceTest {
assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
}
- @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainOnAllowlistChange() throws Exception {
@@ -2227,7 +2223,6 @@ public class NetworkPolicyManagerServiceTest {
assertFalse(mService.isUidNetworkingBlocked(UID_B, false));
}
- @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainOnTempAllowlistChange() throws Exception {
@@ -2266,7 +2261,6 @@ public class NetworkPolicyManagerServiceTest {
&& uidState.procState == procState && uidState.capability == capability;
}
- @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testUidObserverFiltersProcStateChanges() throws Exception {
@@ -2321,15 +2315,15 @@ public class NetworkPolicyManagerServiceTest {
}
waitForUidEventHandlerIdle();
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
- // Doesn't cross any other threshold.
+ // Doesn't cross any threshold, but changes below TOP_THRESHOLD_STATE should always
+ // be processed
callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE - 1, testProcStateSeq++,
PROCESS_CAPABILITY_NONE);
- assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+ assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
}
waitForUidEventHandlerIdle();
}
- @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testUidObserverFiltersStaleChanges() throws Exception {
@@ -2350,28 +2344,27 @@ public class NetworkPolicyManagerServiceTest {
waitForUidEventHandlerIdle();
}
- @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testUidObserverFiltersCapabilityChanges() throws Exception {
int testProcStateSeq = 0;
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
// First callback for uid.
- callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
PROCESS_CAPABILITY_NONE);
assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
}
waitForUidEventHandlerIdle();
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
// The same process-state with one network capability added.
- callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
}
waitForUidEventHandlerIdle();
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
// The same process-state with another network capability added.
- callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
| PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
@@ -2379,11 +2372,21 @@ public class NetworkPolicyManagerServiceTest {
waitForUidEventHandlerIdle();
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
// The same process-state with all capabilities, but no change in network capabilities.
- callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
PROCESS_CAPABILITY_ALL);
assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
}
waitForUidEventHandlerIdle();
+
+ callAndWaitOnUidStateChanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ PROCESS_CAPABILITY_ALL);
+ try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+ // No change in capabilities, but TOP_THRESHOLD_STATE change should always be processed.
+ callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ PROCESS_CAPABILITY_ALL);
+ assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+ }
+ waitForUidEventHandlerIdle();
}
@Test
@@ -2430,7 +2433,6 @@ public class NetworkPolicyManagerServiceTest {
assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
}
- @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testObsoleteHandleUidChanged() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
index 558e2591161c..41c4383a0bec 100644
--- a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
@@ -16,5 +16,11 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ // b/331020193, Move to presubmit early april 2024
+ "name": "FrameworksServicesTests_om"
+ }
]
}
diff --git a/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
index 5a46f8c4beea..06e7002924a7 100644
--- a/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
@@ -8,5 +8,11 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ // b/331020193, Move to presubmit early april 2024
+ "name": "FrameworksServicesTests_os"
+ }
]
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
index 85a73bb22009..f4e724f493c5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
@@ -20,21 +20,13 @@
],
"postsubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.pm."
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ // Presubmit is intentional here while testing with SLO checker.
+ // b/331020193, Move to presubmit early april 2024
+ "name": "FrameworksServicesTests_pm_presubmit"
+ },
+ {
+ // Leave postsubmit here when migrating
+ "name": "FrameworksServicesTests_pm_postsubmit"
}
]
}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
index e9d8b2e709e7..7e7393c3a822 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
@@ -11,5 +11,11 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ // b/331020193, Move to presubmit early april 2024
+ "name": "FrameworksServicesTests_recoverysystem"
+ }
]
} \ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 887e5ee0c58a..e4436966ae03 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -304,8 +304,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mContentRecorder.updateRecording();
// Resize the output surface.
- final Point newSurfaceSize = new Point(Math.round(mSurfaceSize.x / 2f),
- Math.round(mSurfaceSize.y * 2));
+ final Point newSurfaceSize = new Point(Math.round(mSurfaceSize.x / 2f), mSurfaceSize.y * 2);
doReturn(newSurfaceSize).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize(
anyInt());
mContentRecorder.onConfigurationChanged(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 55a00fc0ec89..48fc2dc4bada 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -799,6 +799,7 @@ public class WindowContainerTests extends WindowTestsBase {
verify(child).onConfigurationChanged(any());
}
+ @SuppressWarnings("SelfComparison")
@Test
public void testCompareTo() {
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
index d9cbea95e563..ed89190f8473 100644
--- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
+++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
@@ -181,7 +181,7 @@ class BroadcastResponseStatsTracker {
// We only need to look at the broadcast events that occurred before
// this notification related event.
while (dispatchTimestampsMs.size() > 0
- && dispatchTimestampsMs.peekFirst() < timestampMs) {
+ && dispatchTimestampsMs.peekFirst() <= timestampMs) {
final long dispatchTimestampMs = dispatchTimestampsMs.peekFirst();
final long elapsedDurationMs = timestampMs - dispatchTimestampMs;
// Only increment the counts if the broadcast was sent not too long ago, as
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 70a95400bd9e..d65a4e44440e 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -14,37 +14,22 @@
// limitations under the License.
//
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
// Build the android.test.base library
// ===================================
// This contains the junit.framework and android.test classes that were in
// Android API level 25 excluding those from android.test.runner.
// Also contains the com.android.internal.util.Predicate[s] classes.
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CPL-1.0
- default_applicable_licenses: ["frameworks_base_test-base_license"],
-}
-
-license {
- name: "frameworks_base_test-base_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
- "SPDX-license-identifier-CPL-1.0",
- ],
- license_text: [
- "src/junit/cpl-v10.html",
- ],
-}
-
java_sdk_library {
name: "android.test.base",
- srcs: [":android-test-base-sources"],
+ srcs: [
+ ":android-test-base-sources",
+ ":frameworks-base-test-junit-framework",
+ ],
errorprone: {
javacflags: ["-Xep:DepAnn:ERROR"],
@@ -84,7 +69,10 @@ java_library_static {
],
installable: false,
- srcs: [":android-test-base-sources"],
+ srcs: [
+ ":android-test-base-sources",
+ ":frameworks-base-test-junit-framework",
+ ],
errorprone: {
javacflags: ["-Xep:DepAnn:ERROR"],
@@ -104,8 +92,7 @@ java_library_static {
name: "android.test.base-minus-junit",
srcs: [
- "src/android/**/*.java",
- "src/com/**/*.java",
+ "src/**/*.java",
],
sdk_version: "current",
diff --git a/test-base/hiddenapi/Android.bp b/test-base/hiddenapi/Android.bp
index 1466590ef311..4c59b10ba423 100644
--- a/test-base/hiddenapi/Android.bp
+++ b/test-base/hiddenapi/Android.bp
@@ -15,12 +15,7 @@
//
package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
// Provided solely to contribute information about which hidden parts of the android.test.base
diff --git a/test-junit/Android.bp b/test-junit/Android.bp
new file mode 100644
index 000000000000..8d3d439e034e
--- /dev/null
+++ b/test-junit/Android.bp
@@ -0,0 +1,53 @@
+//
+// 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 {
+ default_applicable_licenses: ["frameworks-base-test-junit-license"],
+}
+
+license {
+ name: "frameworks-base-test-junit-license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-CPL-1.0",
+ ],
+ license_text: [
+ "src/junit/cpl-v10.html",
+ ],
+}
+
+filegroup {
+ name: "frameworks-base-test-junit-framework",
+ srcs: [
+ "src/junit/framework/**/*.java",
+ ],
+ path: "src",
+ visibility: [
+ "//frameworks/base/test-base",
+ ],
+}
+
+filegroup {
+ name: "frameworks-base-test-junit-runner",
+ srcs: [
+ "src/junit/runner/**/*.java",
+ "src/junit/textui/**/*.java",
+ ],
+ path: "src",
+ visibility: [
+ "//frameworks/base/test-runner",
+ ],
+}
diff --git a/test-base/src/junit/MODULE_LICENSE_CPL b/test-junit/src/junit/MODULE_LICENSE_CPL
index e69de29bb2d1..e69de29bb2d1 100644
--- a/test-base/src/junit/MODULE_LICENSE_CPL
+++ b/test-junit/src/junit/MODULE_LICENSE_CPL
diff --git a/test-base/src/junit/README.android b/test-junit/src/junit/README.android
index 1384a1fedda2..1384a1fedda2 100644
--- a/test-base/src/junit/README.android
+++ b/test-junit/src/junit/README.android
diff --git a/test-base/src/junit/cpl-v10.html b/test-junit/src/junit/cpl-v10.html
index 36aa208d4a29..36aa208d4a29 100644
--- a/test-base/src/junit/cpl-v10.html
+++ b/test-junit/src/junit/cpl-v10.html
diff --git a/test-base/src/junit/framework/Assert.java b/test-junit/src/junit/framework/Assert.java
index 3dcc23d71c19..3dcc23d71c19 100644
--- a/test-base/src/junit/framework/Assert.java
+++ b/test-junit/src/junit/framework/Assert.java
diff --git a/test-base/src/junit/framework/AssertionFailedError.java b/test-junit/src/junit/framework/AssertionFailedError.java
index 0d7802c431c6..0d7802c431c6 100644
--- a/test-base/src/junit/framework/AssertionFailedError.java
+++ b/test-junit/src/junit/framework/AssertionFailedError.java
diff --git a/test-base/src/junit/framework/ComparisonCompactor.java b/test-junit/src/junit/framework/ComparisonCompactor.java
index e540f03b87d3..e540f03b87d3 100644
--- a/test-base/src/junit/framework/ComparisonCompactor.java
+++ b/test-junit/src/junit/framework/ComparisonCompactor.java
diff --git a/test-base/src/junit/framework/ComparisonFailure.java b/test-junit/src/junit/framework/ComparisonFailure.java
index 507799328a44..507799328a44 100644
--- a/test-base/src/junit/framework/ComparisonFailure.java
+++ b/test-junit/src/junit/framework/ComparisonFailure.java
diff --git a/test-base/src/junit/framework/Protectable.java b/test-junit/src/junit/framework/Protectable.java
index e1432370cfaf..e1432370cfaf 100644
--- a/test-base/src/junit/framework/Protectable.java
+++ b/test-junit/src/junit/framework/Protectable.java
diff --git a/test-base/src/junit/framework/Test.java b/test-junit/src/junit/framework/Test.java
index a016ee8308f1..a016ee8308f1 100644
--- a/test-base/src/junit/framework/Test.java
+++ b/test-junit/src/junit/framework/Test.java
diff --git a/test-base/src/junit/framework/TestCase.java b/test-junit/src/junit/framework/TestCase.java
index b047ec9e1afc..b047ec9e1afc 100644
--- a/test-base/src/junit/framework/TestCase.java
+++ b/test-junit/src/junit/framework/TestCase.java
diff --git a/test-base/src/junit/framework/TestFailure.java b/test-junit/src/junit/framework/TestFailure.java
index 6662b1fab1b2..6662b1fab1b2 100644
--- a/test-base/src/junit/framework/TestFailure.java
+++ b/test-junit/src/junit/framework/TestFailure.java
diff --git a/test-base/src/junit/framework/TestListener.java b/test-junit/src/junit/framework/TestListener.java
index 9b6944361b9d..9b6944361b9d 100644
--- a/test-base/src/junit/framework/TestListener.java
+++ b/test-junit/src/junit/framework/TestListener.java
diff --git a/test-base/src/junit/framework/TestResult.java b/test-junit/src/junit/framework/TestResult.java
index 3052e94074fd..3052e94074fd 100644
--- a/test-base/src/junit/framework/TestResult.java
+++ b/test-junit/src/junit/framework/TestResult.java
diff --git a/test-base/src/junit/framework/TestSuite.java b/test-junit/src/junit/framework/TestSuite.java
index 336efd1800d7..336efd1800d7 100644
--- a/test-base/src/junit/framework/TestSuite.java
+++ b/test-junit/src/junit/framework/TestSuite.java
diff --git a/test-runner/src/junit/runner/BaseTestRunner.java b/test-junit/src/junit/runner/BaseTestRunner.java
index b2fa16c91da2..b2fa16c91da2 100644
--- a/test-runner/src/junit/runner/BaseTestRunner.java
+++ b/test-junit/src/junit/runner/BaseTestRunner.java
diff --git a/test-runner/src/junit/runner/StandardTestSuiteLoader.java b/test-junit/src/junit/runner/StandardTestSuiteLoader.java
index 808963a5aea0..808963a5aea0 100644
--- a/test-runner/src/junit/runner/StandardTestSuiteLoader.java
+++ b/test-junit/src/junit/runner/StandardTestSuiteLoader.java
diff --git a/test-runner/src/junit/runner/TestRunListener.java b/test-junit/src/junit/runner/TestRunListener.java
index 0e9581989eee..0e9581989eee 100644
--- a/test-runner/src/junit/runner/TestRunListener.java
+++ b/test-junit/src/junit/runner/TestRunListener.java
diff --git a/test-runner/src/junit/runner/TestSuiteLoader.java b/test-junit/src/junit/runner/TestSuiteLoader.java
index 9cc6d81e125e..9cc6d81e125e 100644
--- a/test-runner/src/junit/runner/TestSuiteLoader.java
+++ b/test-junit/src/junit/runner/TestSuiteLoader.java
diff --git a/test-runner/src/junit/runner/Version.java b/test-junit/src/junit/runner/Version.java
index dd88c03372c8..dd88c03372c8 100644
--- a/test-runner/src/junit/runner/Version.java
+++ b/test-junit/src/junit/runner/Version.java
diff --git a/test-runner/src/junit/runner/package-info.java b/test-junit/src/junit/runner/package-info.java
index 364e3621456e..364e3621456e 100644
--- a/test-runner/src/junit/runner/package-info.java
+++ b/test-junit/src/junit/runner/package-info.java
diff --git a/test-runner/src/junit/textui/ResultPrinter.java b/test-junit/src/junit/textui/ResultPrinter.java
index b4914529bf4f..b4914529bf4f 100644
--- a/test-runner/src/junit/textui/ResultPrinter.java
+++ b/test-junit/src/junit/textui/ResultPrinter.java
diff --git a/test-runner/src/junit/textui/TestRunner.java b/test-junit/src/junit/textui/TestRunner.java
index 046448e5e76a..046448e5e76a 100644
--- a/test-runner/src/junit/textui/TestRunner.java
+++ b/test-junit/src/junit/textui/TestRunner.java
diff --git a/test-runner/src/junit/textui/package-info.java b/test-junit/src/junit/textui/package-info.java
index 28b2ef46b582..28b2ef46b582 100644
--- a/test-runner/src/junit/textui/package-info.java
+++ b/test-junit/src/junit/textui/package-info.java
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
new file mode 100644
index 000000000000..236d704ef742
--- /dev/null
+++ b/test-legacy/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ ],
+}
+
+java_library {
+ name: "android.test.legacy",
+ sdk_version: "current",
+ libs: [
+ "android.test.mock.stubs",
+ "junit",
+ ],
+ static_libs: [
+ "android.test.base-minus-junit",
+ "android.test.runner-minus-junit",
+ ],
+ dist: {
+ targets: [
+ "sdk",
+ ],
+ },
+}
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
deleted file mode 100644
index da9dc2505805..000000000000
--- a/test-legacy/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
-ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
-
-# Build the android.test.legacy library
-# =====================================
-# Built against the SDK so that it can be statically included in APKs
-# without breaking link type checks.
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.legacy
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_JAVA_LIBRARIES := junit android.test.mock.stubs
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android.test.base-minus-junit \
- android.test.runner-minus-junit \
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-$(call declare-license-metadata,$(full_classes_jar),\
- SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS,\
- notice,$(LOCAL_PATH)/../NOTICE,Android,frameworks/base)
-
-# Archive a copy of the classes.jar in SDK build.
-$(call dist-for-goals,sdk,$(full_classes_jar):android.test.legacy.jar)
-
-endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index f37d2d17973e..e29d321e5105 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -17,12 +17,7 @@
// Build the android.test.mock library
// ===================================
package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
java_sdk_library {
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index 21e09d3221ce..6b5be3cba204 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -14,29 +14,19 @@
// limitations under the License.
//
-// Build the android.test.runner library
-// =====================================
package {
- // See: http://go/android-license-faq
- default_applicable_licenses: ["frameworks_base_test-runner_license"],
-}
-
-license {
- name: "frameworks_base_test-runner_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
- "SPDX-license-identifier-CPL-1.0",
- ],
- license_text: [
- "src/junit/cpl-v10.html",
- ],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
+// Build the android.test.runner library
+// =====================================
java_sdk_library {
name: "android.test.runner",
- srcs: [":android-test-runner-sources"],
+ srcs: [
+ ":android-test-runner-sources",
+ ":frameworks-base-test-junit-runner",
+ ],
errorprone: {
javacflags: ["-Xep:DepAnn:ERROR"],
diff --git a/test-runner/src/junit/MODULE_LICENSE_CPL b/test-runner/src/junit/MODULE_LICENSE_CPL
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/test-runner/src/junit/MODULE_LICENSE_CPL
+++ /dev/null
diff --git a/test-runner/src/junit/README.android b/test-runner/src/junit/README.android
deleted file mode 100644
index 1384a1fedda2..000000000000
--- a/test-runner/src/junit/README.android
+++ /dev/null
@@ -1,11 +0,0 @@
-URL: https://github.com/junit-team/junit4
-License: Common Public License Version 1.0
-License File: cpl-v10.html
-
-This is JUnit 4.10 source that was previously part of the Android Public API.
-Where necessary it has been patched to be compatible (according to Android API
-requirements) with JUnit 3.8.
-
-These are copied here to ensure that the android.test.runner target remains
-compatible with the last version of the Android API (25) that contained these
-classes even when external/junit is upgraded to a later version.
diff --git a/test-runner/src/junit/cpl-v10.html b/test-runner/src/junit/cpl-v10.html
deleted file mode 100644
index 36aa208d4a29..000000000000
--- a/test-runner/src/junit/cpl-v10.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
-<HTML>
-<HEAD>
-<TITLE>Common Public License - v 1.0</TITLE>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-</HEAD>
-
-<BODY BGCOLOR="#FFFFFF" VLINK="#800000">
-
-
-<P ALIGN="CENTER"><B>Common Public License - v 1.0</B>
-<P><B></B><FONT SIZE="3"></FONT>
-<P><FONT SIZE="3"></FONT><FONT SIZE="2">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"><B>1. DEFINITIONS</B></FONT>
-<P><FONT SIZE="2">"Contribution" means:</FONT>
-
-<UL><FONT SIZE="2">a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and<BR CLEAR="LEFT">
-b) in the case of each subsequent Contributor:</FONT></UL>
-
-
-<UL><FONT SIZE="2">i) changes to the Program, and</FONT></UL>
-
-
-<UL><FONT SIZE="2">ii) additions to the Program;</FONT></UL>
-
-
-<UL><FONT SIZE="2">where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. </FONT><FONT SIZE="2">A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. </FONT><FONT SIZE="2">Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. </FONT></UL>
-
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">"Contributor" means any person or entity that distributes the Program.</FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. </FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2">"Program" means the Contributions distributed in accordance with this Agreement.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.</FONT>
-<P><FONT SIZE="2"><B></B></FONT>
-<P><FONT SIZE="2"><B>2. GRANT OF RIGHTS</B></FONT>
-
-<UL><FONT SIZE="2"></FONT><FONT SIZE="2">a) </FONT><FONT SIZE="2">Subject to the terms of this Agreement, each Contributor hereby grants</FONT><FONT SIZE="2"> Recipient a non-exclusive, worldwide, royalty-free copyright license to</FONT><FONT SIZE="2" COLOR="#FF0000"> </FONT><FONT SIZE="2">reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.</FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT><FONT SIZE="2">b) Subject to the terms of this Agreement, each Contributor hereby grants </FONT><FONT SIZE="2">Recipient a non-exclusive, worldwide,</FONT><FONT SIZE="2" COLOR="#008000"> </FONT><FONT SIZE="2">royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. </FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT></UL>
-
-
-<UL><FONT SIZE="2">c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.</FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT></UL>
-
-
-<UL><FONT SIZE="2">d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. </FONT></UL>
-
-
-<UL><FONT SIZE="2"></FONT></UL>
-
-<P><FONT SIZE="2"><B>3. REQUIREMENTS</B></FONT>
-<P><FONT SIZE="2"><B></B>A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:</FONT>
-
-<UL><FONT SIZE="2">a) it complies with the terms and conditions of this Agreement; and</FONT></UL>
-
-
-<UL><FONT SIZE="2">b) its license agreement:</FONT></UL>
-
-
-<UL><FONT SIZE="2">i) effectively disclaims</FONT><FONT SIZE="2"> on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; </FONT></UL>
-
-
-<UL><FONT SIZE="2">ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; </FONT></UL>
-
-
-<UL><FONT SIZE="2">iii)</FONT><FONT SIZE="2"> states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and</FONT></UL>
-
-
-<UL><FONT SIZE="2">iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.</FONT><FONT SIZE="2" COLOR="#0000FF"> </FONT><FONT SIZE="2" COLOR="#FF0000"></FONT></UL>
-
-
-<UL><FONT SIZE="2" COLOR="#FF0000"></FONT><FONT SIZE="2"></FONT></UL>
-
-<P><FONT SIZE="2">When the Program is made available in source code form:</FONT>
-
-<UL><FONT SIZE="2">a) it must be made available under this Agreement; and </FONT></UL>
-
-
-<UL><FONT SIZE="2">b) a copy of this Agreement must be included with each copy of the Program. </FONT></UL>
-
-<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT>
-<P><FONT SIZE="2" COLOR="#0000FF"><STRIKE></STRIKE></FONT><FONT SIZE="2">Contributors may not remove or alter any copyright notices contained within the Program. </FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. </FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"><B>4. COMMERCIAL DISTRIBUTION</B></FONT>
-<P><FONT SIZE="2">Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.</FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2" COLOR="#0000FF"></FONT>
-<P><FONT SIZE="2" COLOR="#0000FF"></FONT><FONT SIZE="2"><B>5. NO WARRANTY</B></FONT>
-<P><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is</FONT><FONT SIZE="2"> solely responsible for determining the appropriateness of using and distributing </FONT><FONT SIZE="2">the Program</FONT><FONT SIZE="2"> and assumes all risks associated with its exercise of rights under this Agreement</FONT><FONT SIZE="2">, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, </FONT><FONT SIZE="2">programs or equipment, and unavailability or interruption of operations</FONT><FONT SIZE="2">. </FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"><B>6. DISCLAIMER OF LIABILITY</B></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES </FONT><FONT SIZE="2">(INCLUDING WITHOUT LIMITATION LOST PROFITS),</FONT><FONT SIZE="2"> HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"><B>7. GENERAL</B></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2">If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. </FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. </FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2">Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to </FONT><FONT SIZE="2">publish new versions (including revisions) of this Agreement from time to </FONT><FONT SIZE="2">time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. </FONT><FONT SIZE="2">Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new </FONT><FONT SIZE="2">version. </FONT><FONT SIZE="2">Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, </FONT><FONT SIZE="2">by implication, estoppel or otherwise</FONT><FONT SIZE="2">.</FONT><FONT SIZE="2"> All rights in the Program not expressly granted under this Agreement are reserved.</FONT>
-<P><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2">This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.</FONT>
-<P><FONT SIZE="2"></FONT><FONT SIZE="2"></FONT>
-<P><FONT SIZE="2"></FONT>
-
-</BODY>
-
-</HTML> \ No newline at end of file
diff --git a/test-runner/tests/Android.bp b/test-runner/tests/Android.bp
index ac21bcb9d124..aad2bee8cb84 100644
--- a/test-runner/tests/Android.bp
+++ b/test-runner/tests/Android.bp
@@ -13,12 +13,7 @@
// limitations under the License.
package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
android_test {
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index e0e6c4c43b16..2c5fdd3228ed 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -28,8 +28,10 @@ android_test {
static_libs: [
"junit",
"mockito-target-extended-minus-junit4",
+ "flag-junit",
"frameworks-base-testutils",
"androidx.test.rules",
+ "PlatformProperties",
"services.core",
"services.net",
"truth",
diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
new file mode 100644
index 000000000000..081da11f2aa8
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.crashrecovery.flags.Flags;
+import android.net.ConnectivityModuleConnector;
+import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.DeviceConfig;
+import android.util.AtomicFile;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.server.RescueParty.RescuePartyObserver;
+import com.android.server.pm.ApexManager;
+import com.android.server.rollback.RollbackPackageHealthObserver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Test CrashRecovery, integration tests that include PackageWatchdog, RescueParty and
+ * RollbackPackageHealthObserver
+ */
+public class CrashRecoveryTest {
+ private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
+ "persist.device_config.configuration.disable_rescue_party";
+
+ private static final String APP_A = "com.package.a";
+ private static final String APP_B = "com.package.b";
+ private static final String APP_C = "com.package.c";
+ private static final long VERSION_CODE = 1L;
+ private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
+
+ private static final RollbackInfo ROLLBACK_INFO_LOW = getRollbackInfo(APP_A, VERSION_CODE, 1,
+ PackageManager.ROLLBACK_USER_IMPACT_LOW);
+ private static final RollbackInfo ROLLBACK_INFO_HIGH = getRollbackInfo(APP_B, VERSION_CODE, 2,
+ PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+ private static final RollbackInfo ROLLBACK_INFO_MANUAL = getRollbackInfo(APP_C, VERSION_CODE, 3,
+ PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL);
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ private final TestClock mTestClock = new TestClock();
+ private TestLooper mTestLooper;
+ private Context mSpyContext;
+ // Keep track of all created watchdogs to apply device config changes
+ private List<PackageWatchdog> mAllocatedWatchdogs;
+ @Mock
+ private ConnectivityModuleConnector mConnectivityModuleConnector;
+ @Mock
+ private PackageManager mMockPackageManager;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private ApexManager mApexManager;
+ @Mock
+ RollbackManager mRollbackManager;
+ // Mock only sysprop apis
+ private PackageWatchdog.BootThreshold mSpyBootThreshold;
+ @Captor
+ private ArgumentCaptor<ConnectivityModuleHealthListener> mConnectivityModuleCallbackCaptor;
+ private MockitoSession mSession;
+ private HashMap<String, String> mSystemSettingsMap;
+ private HashMap<String, String> mCrashRecoveryPropertiesMap;
+
+ @Before
+ public void setUp() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ MockitoAnnotations.initMocks(this);
+ new File(InstrumentationRegistry.getContext().getFilesDir(),
+ "package-watchdog.xml").delete();
+ adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG,
+ Manifest.permission.WRITE_DEVICE_CONFIG);
+ mTestLooper = new TestLooper();
+ mSpyContext = spy(InstrumentationRegistry.getContext());
+ when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).then(inv -> {
+ final PackageInfo res = new PackageInfo();
+ res.packageName = inv.getArgument(0);
+ res.setLongVersionCode(VERSION_CODE);
+ return res;
+ });
+ mSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .spyStatic(SystemProperties.class)
+ .spyStatic(RescueParty.class)
+ .startMocking();
+ mSystemSettingsMap = new HashMap<>();
+
+ // Mock SystemProperties setter and various getters
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ String value = invocationOnMock.getArgument(1);
+
+ mSystemSettingsMap.put(key, value);
+ return null;
+ }
+ ).when(() -> SystemProperties.set(anyString(), anyString()));
+
+ doAnswer((Answer<Integer>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ int defaultValue = invocationOnMock.getArgument(1);
+
+ String storedValue = mSystemSettingsMap.get(key);
+ return storedValue == null ? defaultValue : Integer.parseInt(storedValue);
+ }
+ ).when(() -> SystemProperties.getInt(anyString(), anyInt()));
+
+ doAnswer((Answer<Long>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ long defaultValue = invocationOnMock.getArgument(1);
+
+ String storedValue = mSystemSettingsMap.get(key);
+ return storedValue == null ? defaultValue : Long.parseLong(storedValue);
+ }
+ ).when(() -> SystemProperties.getLong(anyString(), anyLong()));
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ boolean defaultValue = invocationOnMock.getArgument(1);
+
+ String storedValue = mSystemSettingsMap.get(key);
+ return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue);
+ }
+ ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean()));
+
+ SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+ SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ Boolean.toString(true), false);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT), false);
+
+ mAllocatedWatchdogs = new ArrayList<>();
+ RescuePartyObserver.reset();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ dropShellPermissions();
+ mSession.finishMocking();
+ // Clean up listeners since too many listeners will delay notifications significantly
+ for (PackageWatchdog watchdog : mAllocatedWatchdogs) {
+ watchdog.removePropertyChangedListener();
+ }
+ mAllocatedWatchdogs.clear();
+ }
+
+ @Test
+ public void testBootLoopWithRescueParty() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(1);
+ int bootCounter = 0;
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(1);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(2);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+
+ int bootLoopThreshold = PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - bootCounter;
+ for (int i = 0; i < bootLoopThreshold; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(3);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(4);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(4);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(5);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(5);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(6);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(6);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(7);
+ }
+
+ @Test
+ public void testBootLoopWithRollbackPackageHealthObserver() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ RollbackPackageHealthObserver rollbackObserver =
+ setUpRollbackPackageHealthObserver(watchdog);
+
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+ int bootCounter = 0;
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ 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));
+
+ int bootLoopThreshold = PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - bootCounter;
+ for (int i = 0; i < bootLoopThreshold; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rollbackObserver).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+
+ // Update the list of available rollbacks after executing bootloop mitigation once
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL));
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+ }
+
+ @Test
+ public void testBootLoopWithRescuePartyAndRollbackPackageHealthObserver() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
+ RollbackPackageHealthObserver rollbackObserver =
+ setUpRollbackPackageHealthObserver(watchdog);
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(1);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+ int bootCounter = 0;
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(1);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(2);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+ 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));
+
+ int bootLoopThreshold = PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - bootCounter;
+ for (int i = 0; i < bootLoopThreshold; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(3);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(4);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(4);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(5);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(5);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(6);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(6);
+ 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));
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(6);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(7);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+ }
+
+ RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) {
+ RollbackPackageHealthObserver rollbackObserver =
+ spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager));
+ when(mSpyContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_LOW,
+ ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL));
+ when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
+
+ watchdog.registerHealthObserver(rollbackObserver);
+ return rollbackObserver;
+ }
+
+ RescuePartyObserver setUpRescuePartyObserver(PackageWatchdog watchdog) {
+ setCrashRecoveryPropRescueBootCount(0);
+ RescuePartyObserver rescuePartyObserver = spy(RescuePartyObserver.getInstance(mSpyContext));
+ assertFalse(RescueParty.isRebootPropertySet());
+ watchdog.registerHealthObserver(rescuePartyObserver);
+ return rescuePartyObserver;
+ }
+
+ private static RollbackInfo getRollbackInfo(String packageName, long versionCode,
+ int rollbackId, int rollbackUserImpact) {
+ VersionedPackage appFrom = new VersionedPackage(packageName, versionCode + 1);
+ VersionedPackage appTo = new VersionedPackage(packageName, versionCode);
+ PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appFrom, appTo, null,
+ null, false, false, null);
+ RollbackInfo rollbackInfo = new RollbackInfo(rollbackId, List.of(packageRollbackInfo),
+ false, null, 111, rollbackUserImpact);
+ return rollbackInfo;
+ }
+
+ private void adoptShellPermissions(String... permissions) {
+ androidx.test.platform.app.InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity(permissions);
+ }
+
+ private void dropShellPermissions() {
+ androidx.test.platform.app.InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+
+ private PackageWatchdog createWatchdog() {
+ return createWatchdog(new TestController(), true /* withPackagesReady */);
+ }
+
+ private PackageWatchdog createWatchdog(TestController controller, boolean withPackagesReady) {
+ AtomicFile policyFile =
+ new AtomicFile(new File(mSpyContext.getFilesDir(), "package-watchdog.xml"));
+ Handler handler = new Handler(mTestLooper.getLooper());
+ PackageWatchdog watchdog =
+ new PackageWatchdog(mSpyContext, policyFile, handler, handler, controller,
+ mConnectivityModuleConnector, mTestClock);
+ mockCrashRecoveryProperties(watchdog);
+
+ // Verify controller is not automatically started
+ assertThat(controller.mIsEnabled).isFalse();
+ if (withPackagesReady) {
+ // Only capture the NetworkStack callback for the latest registered watchdog
+ reset(mConnectivityModuleConnector);
+ watchdog.onPackagesReady();
+ // Verify controller by default is started when packages are ready
+ assertThat(controller.mIsEnabled).isTrue();
+
+ verify(mConnectivityModuleConnector).registerHealthListener(
+ mConnectivityModuleCallbackCaptor.capture());
+ }
+ mAllocatedWatchdogs.add(watchdog);
+ return watchdog;
+ }
+
+ // Mock CrashRecoveryProperties as they cannot be accessed due to SEPolicy restrictions
+ private void mockCrashRecoveryProperties(PackageWatchdog watchdog) {
+ mCrashRecoveryPropertiesMap = new HashMap<>();
+
+ // mock properties in RescueParty
+ try {
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.attempting_factory_reset", "false");
+ return Boolean.parseBoolean(storedValue);
+ }).when(() -> RescueParty.isFactoryResetPropertySet());
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ boolean value = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.attempting_factory_reset",
+ Boolean.toString(value));
+ return null;
+ }).when(() -> RescueParty.setFactoryResetProperty(anyBoolean()));
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.attempting_reboot", "false");
+ return Boolean.parseBoolean(storedValue);
+ }).when(() -> RescueParty.isRebootPropertySet());
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ boolean value = invocationOnMock.getArgument(0);
+ setCrashRecoveryPropAttemptingReboot(value);
+ return null;
+ }).when(() -> RescueParty.setRebootProperty(anyBoolean()));
+
+ doAnswer((Answer<Long>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("persist.crashrecovery.last_factory_reset", "0");
+ return Long.parseLong(storedValue);
+ }).when(() -> RescueParty.getLastFactoryResetTimeMs());
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ long value = invocationOnMock.getArgument(0);
+ setCrashRecoveryPropLastFactoryReset(value);
+ return null;
+ }).when(() -> RescueParty.setLastFactoryResetTimeMs(anyLong()));
+
+ doAnswer((Answer<Integer>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.max_rescue_level_attempted", "0");
+ return Integer.parseInt(storedValue);
+ }).when(() -> RescueParty.getMaxRescueLevelAttempted());
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ int value = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.max_rescue_level_attempted",
+ Integer.toString(value));
+ return null;
+ }).when(() -> RescueParty.setMaxRescueLevelAttempted(anyInt()));
+
+ } catch (Exception e) {
+ // tests will fail, just printing the error
+ System.out.println("Error while mocking crashrecovery properties " + e.getMessage());
+ }
+
+ try {
+ if (Flags.recoverabilityDetection()) {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+ } else {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+ }
+
+ doAnswer((Answer<Integer>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.rescue_boot_count", "0");
+ return Integer.parseInt(storedValue);
+ }).when(mSpyBootThreshold).getCount();
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ int count = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.rescue_boot_count",
+ Integer.toString(count));
+ return null;
+ }).when(mSpyBootThreshold).setCount(anyInt());
+
+ doAnswer((Answer<Integer>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.boot_mitigation_count", "0");
+ return Integer.parseInt(storedValue);
+ }).when(mSpyBootThreshold).getMitigationCount();
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ int count = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.boot_mitigation_count",
+ Integer.toString(count));
+ return null;
+ }).when(mSpyBootThreshold).setMitigationCount(anyInt());
+
+ doAnswer((Answer<Long>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.rescue_boot_start", "0");
+ return Long.parseLong(storedValue);
+ }).when(mSpyBootThreshold).getStart();
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ long count = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.rescue_boot_start",
+ Long.toString(count));
+ return null;
+ }).when(mSpyBootThreshold).setStart(anyLong());
+
+ doAnswer((Answer<Long>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.boot_mitigation_start", "0");
+ return Long.parseLong(storedValue);
+ }).when(mSpyBootThreshold).getMitigationStart();
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ long count = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.boot_mitigation_start",
+ Long.toString(count));
+ return null;
+ }).when(mSpyBootThreshold).setMitigationStart(anyLong());
+
+ Field mBootThresholdField = watchdog.getClass().getDeclaredField("mBootThreshold");
+ mBootThresholdField.setAccessible(true);
+ mBootThresholdField.set(watchdog, mSpyBootThreshold);
+ } catch (Exception e) {
+ // tests will fail, just printing the error
+ System.out.println("Error detected while spying BootThreshold" + e.getMessage());
+ }
+ }
+
+ private void setCrashRecoveryPropRescueBootCount(int count) {
+ mCrashRecoveryPropertiesMap.put("crashrecovery.rescue_boot_count",
+ Integer.toString(count));
+ }
+
+ private void setCrashRecoveryPropAttemptingReboot(boolean value) {
+ mCrashRecoveryPropertiesMap.put("crashrecovery.attempting_reboot",
+ Boolean.toString(value));
+ }
+
+ private void setCrashRecoveryPropLastFactoryReset(long value) {
+ mCrashRecoveryPropertiesMap.put("persist.crashrecovery.last_factory_reset",
+ Long.toString(value));
+ }
+
+ private static class TestController extends ExplicitHealthCheckController {
+ TestController() {
+ super(null /* controller */);
+ }
+
+ private boolean mIsEnabled;
+ private List<String> mSupportedPackages = new ArrayList<>();
+ private List<String> mRequestedPackages = new ArrayList<>();
+ private Consumer<List<PackageConfig>> mSupportedConsumer;
+ private List<Set> mSyncRequests = new ArrayList<>();
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mIsEnabled = enabled;
+ if (!mIsEnabled) {
+ mSupportedPackages.clear();
+ }
+ }
+
+ @Override
+ public void setCallbacks(Consumer<String> passedConsumer,
+ Consumer<List<PackageConfig>> supportedConsumer, Runnable notifySyncRunnable) {
+ mSupportedConsumer = supportedConsumer;
+ }
+
+ @Override
+ public void syncRequests(Set<String> packages) {
+ mSyncRequests.add(packages);
+ mRequestedPackages.clear();
+ if (mIsEnabled) {
+ packages.retainAll(mSupportedPackages);
+ mRequestedPackages.addAll(packages);
+ List<PackageConfig> packageConfigs = new ArrayList<>();
+ for (String packageName: packages) {
+ packageConfigs.add(new PackageConfig(packageName, SHORT_DURATION));
+ }
+ mSupportedConsumer.accept(packageConfigs);
+ } else {
+ mSupportedConsumer.accept(Collections.emptyList());
+ }
+ }
+ }
+
+ private static class TestClock implements PackageWatchdog.SystemClock {
+ // Note 0 is special to the internal clock of PackageWatchdog. We need to start from
+ // a non-zero value in order not to disrupt the logic of PackageWatchdog.
+ private long mUpTimeMillis = 1;
+ @Override
+ public long uptimeMillis() {
+ return mUpTimeMillis;
+ }
+ }
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 755636aef7ed..4f27e06083ba 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -36,29 +36,33 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
import android.net.ConnectivityModuleConnector;
import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener;
import android.os.Handler;
import android.os.SystemProperties;
import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.util.AtomicFile;
-import android.util.LongArrayQueue;
import android.util.Xml;
+import android.utils.LongArrayQueue;
+import android.utils.XmlUtils;
import androidx.test.InstrumentationRegistry;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
-import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.PackageWatchdog.HealthCheckState;
import com.android.server.PackageWatchdog.MonitoredPackage;
+import com.android.server.PackageWatchdog.ObserverInternal;
import com.android.server.PackageWatchdog.PackageHealthObserver;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@@ -99,6 +103,10 @@ public class PackageWatchdogTest {
private static final String OBSERVER_NAME_4 = "observer4";
private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private final TestClock mTestClock = new TestClock();
private TestLooper mTestLooper;
private Context mSpyContext;
@@ -128,6 +136,7 @@ public class PackageWatchdogTest {
@Before
public void setUp() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
MockitoAnnotations.initMocks(this);
new File(InstrumentationRegistry.getContext().getFilesDir(),
"package-watchdog.xml").delete();
@@ -444,6 +453,7 @@ public class PackageWatchdogTest {
*/
@Test
public void testPackageFailureNotifyAllDifferentImpacts() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver observerNone = new TestObserver(OBSERVER_NAME_1,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
@@ -488,6 +498,52 @@ public class PackageWatchdogTest {
assertThat(observerLowPackages).containsExactly(APP_A);
}
+ @Test
+ public void testPackageFailureNotifyAllDifferentImpactsRecoverability() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observerNone = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
+ TestObserver observerHigh = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+ TestObserver observerMid = new TestObserver(OBSERVER_NAME_3,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+ TestObserver observerLow = new TestObserver(OBSERVER_NAME_4,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
+
+ // Start observing for all impact observers
+ watchdog.startObservingHealth(observerNone, Arrays.asList(APP_A, APP_B, APP_C, APP_D),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerHigh, Arrays.asList(APP_A, APP_B, APP_C),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerMid, Arrays.asList(APP_A, APP_B),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerLow, Arrays.asList(APP_A),
+ SHORT_DURATION);
+
+ // Then fail all apps above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE),
+ new VersionedPackage(APP_B, VERSION_CODE),
+ new VersionedPackage(APP_C, VERSION_CODE),
+ new VersionedPackage(APP_D, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify least impact observers are notifed of package failures
+ List<String> observerNonePackages = observerNone.mMitigatedPackages;
+ List<String> observerHighPackages = observerHigh.mMitigatedPackages;
+ List<String> observerMidPackages = observerMid.mMitigatedPackages;
+ List<String> observerLowPackages = observerLow.mMitigatedPackages;
+
+ // APP_D failure observed by only observerNone is not caught cos its impact is none
+ assertThat(observerNonePackages).isEmpty();
+ // APP_C failure is caught by observerHigh cos it's the lowest impact observer
+ assertThat(observerHighPackages).containsExactly(APP_C);
+ // APP_B failure is caught by observerMid cos it's the lowest impact observer
+ assertThat(observerMidPackages).containsExactly(APP_B);
+ // APP_A failure is caught by observerLow cos it's the lowest impact observer
+ assertThat(observerLowPackages).containsExactly(APP_A);
+ }
+
/**
* Test package failure and least impact observers are notified successively.
* State transistions:
@@ -501,6 +557,7 @@ public class PackageWatchdogTest {
*/
@Test
public void testPackageFailureNotifyLeastImpactSuccessively() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
@@ -563,11 +620,76 @@ public class PackageWatchdogTest {
assertThat(observerSecond.mMitigatedPackages).isEmpty();
}
+ @Test
+ public void testPackageFailureNotifyLeastImpactSuccessivelyRecoverability() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
+ TestObserver observerSecond = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+
+ // Start observing for observerFirst and observerSecond with failure handling
+ watchdog.startObservingHealth(observerFirst, Arrays.asList(APP_A), LONG_DURATION);
+ watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION);
+
+ // Then fail APP_A above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify only observerFirst is notifed
+ assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A);
+ assertThat(observerSecond.mMitigatedPackages).isEmpty();
+
+ // After observerFirst handles failure, next action it has is high impact
+ observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
+ observerFirst.mMitigatedPackages.clear();
+ observerSecond.mMitigatedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify only observerSecond is notifed cos it has least impact
+ assertThat(observerSecond.mMitigatedPackages).containsExactly(APP_A);
+ assertThat(observerFirst.mMitigatedPackages).isEmpty();
+
+ // After observerSecond handles failure, it has no further actions
+ observerSecond.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ observerFirst.mMitigatedPackages.clear();
+ observerSecond.mMitigatedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify only observerFirst is notifed cos it has the only action
+ assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A);
+ assertThat(observerSecond.mMitigatedPackages).isEmpty();
+
+ // After observerFirst handles failure, it too has no further actions
+ observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ observerFirst.mMitigatedPackages.clear();
+ observerSecond.mMitigatedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify no observer is notified cos no actions left
+ assertThat(observerFirst.mMitigatedPackages).isEmpty();
+ assertThat(observerSecond.mMitigatedPackages).isEmpty();
+ }
+
/**
* Test package failure and notifies only one observer even with observer impact tie.
*/
@Test
public void testPackageFailureNotifyOneSameImpact() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
@@ -588,6 +710,28 @@ public class PackageWatchdogTest {
assertThat(observer2.mMitigatedPackages).isEmpty();
}
+ @Test
+ public void testPackageFailureNotifyOneSameImpactRecoverabilityDetection() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+
+ // Start observing for observer1 and observer2 with failure handling
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+ // Then fail APP_A above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify only one observer is notifed
+ assertThat(observer1.mMitigatedPackages).containsExactly(APP_A);
+ assertThat(observer2.mMitigatedPackages).isEmpty();
+ }
+
/**
* Test package passing explicit health checks does not fail and vice versa.
*/
@@ -818,6 +962,7 @@ public class PackageWatchdogTest {
@Test
public void testNetworkStackFailure() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
final PackageWatchdog wd = createWatchdog();
// Start observing with failure handling
@@ -835,6 +980,25 @@ public class PackageWatchdogTest {
assertThat(observer.mMitigatedPackages).containsExactly(APP_A);
}
+ @Test
+ public void testNetworkStackFailureRecoverabilityDetection() {
+ final PackageWatchdog wd = createWatchdog();
+
+ // Start observing with failure handling
+ TestObserver observer = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
+ wd.startObservingHealth(observer, Collections.singletonList(APP_A), SHORT_DURATION);
+
+ // Notify of NetworkStack failure
+ mConnectivityModuleCallbackCaptor.getValue().onNetworkStackFailure(APP_A);
+
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
+ // Verify the NetworkStack observer is notified
+ assertThat(observer.mMitigatedPackages).isEmpty();
+ }
+
/** Test default values are used when device property is invalid. */
@Test
public void testInvalidConfig_watchdogTriggerFailureCount() {
@@ -1045,6 +1209,7 @@ public class PackageWatchdogTest {
/** Ensure that boot loop mitigation is done when the number of boots meets the threshold. */
@Test
public void testBootLoopDetection_meetsThreshold() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
watchdog.registerHealthObserver(bootObserver);
@@ -1054,6 +1219,16 @@ public class PackageWatchdogTest {
assertThat(bootObserver.mitigatedBootLoop()).isTrue();
}
+ @Test
+ public void testBootLoopDetection_meetsThresholdRecoverability() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD; i++) {
+ watchdog.noteBoot();
+ }
+ assertThat(bootObserver.mitigatedBootLoop()).isTrue();
+ }
/**
* Ensure that boot loop mitigation is not done when the number of boots does not meet the
@@ -1071,10 +1246,43 @@ public class PackageWatchdogTest {
}
/**
+ * Ensure that boot loop mitigation is not done when the number of boots does not meet the
+ * threshold.
+ */
+ @Test
+ public void testBootLoopDetection_doesNotMeetThresholdRecoverabilityLowImpact() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; i++) {
+ watchdog.noteBoot();
+ }
+ assertThat(bootObserver.mitigatedBootLoop()).isFalse();
+ }
+
+ /**
+ * Ensure that boot loop mitigation is not done when the number of boots does not meet the
+ * threshold.
+ */
+ @Test
+ public void testBootLoopDetection_doesNotMeetThresholdRecoverabilityHighImpact() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_80);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - 1; i++) {
+ watchdog.noteBoot();
+ }
+ assertThat(bootObserver.mitigatedBootLoop()).isFalse();
+ }
+
+ /**
* Ensure that boot loop mitigation is done for the observer with the lowest user impact
*/
@Test
public void testBootLoopMitigationDoneForLowestUserImpact() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver bootObserver1 = new TestObserver(OBSERVER_NAME_1);
bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
@@ -1089,11 +1297,28 @@ public class PackageWatchdogTest {
assertThat(bootObserver2.mitigatedBootLoop()).isFalse();
}
+ @Test
+ public void testBootLoopMitigationDoneForLowestUserImpactRecoverability() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver1 = new TestObserver(OBSERVER_NAME_1);
+ bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
+ TestObserver bootObserver2 = new TestObserver(OBSERVER_NAME_2);
+ bootObserver2.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+ watchdog.registerHealthObserver(bootObserver1);
+ watchdog.registerHealthObserver(bootObserver2);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD; i++) {
+ watchdog.noteBoot();
+ }
+ assertThat(bootObserver1.mitigatedBootLoop()).isTrue();
+ assertThat(bootObserver2.mitigatedBootLoop()).isFalse();
+ }
+
/**
* Ensure that the correct mitigation counts are sent to the boot loop observer.
*/
@Test
public void testMultipleBootLoopMitigation() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
watchdog.registerHealthObserver(bootObserver);
@@ -1114,6 +1339,64 @@ public class PackageWatchdogTest {
assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
}
+ @Test
+ public void testMultipleBootLoopMitigationRecoverabilityLowImpact() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; j++) {
+ watchdog.noteBoot();
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; j++) {
+ watchdog.noteBoot();
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
+ }
+
+ @Test
+ public void testMultipleBootLoopMitigationRecoverabilityHighImpact() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_80);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - 1; j++) {
+ watchdog.noteBoot();
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - 1; j++) {
+ watchdog.noteBoot();
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
+ }
+
/**
* Ensure that passing a null list of failed packages does not cause any mitigation logic to
* execute.
@@ -1304,6 +1587,78 @@ public class PackageWatchdogTest {
}
/**
+ * Ensure that a {@link ObserverInternal} may be correctly written and read in order to persist
+ * across reboots.
+ */
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testWritingAndReadingObserverInternalRecoverability() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ LongArrayQueue mitigationCalls = new LongArrayQueue();
+ mitigationCalls.addLast(1000);
+ mitigationCalls.addLast(2000);
+ mitigationCalls.addLast(3000);
+ MonitoredPackage writePkg = watchdog.newMonitoredPackage(
+ "test.package", 1000, 2000, true, mitigationCalls);
+ final int bootMitigationCount = 4;
+ ObserverInternal writeObserver = new ObserverInternal("test", List.of(writePkg),
+ bootMitigationCount);
+
+ // Write the observer
+ File tmpFile = File.createTempFile("observer-watchdog-test", ".xml");
+ AtomicFile testFile = new AtomicFile(tmpFile);
+ FileOutputStream stream = testFile.startWrite();
+ TypedXmlSerializer outputSerializer = Xml.resolveSerializer(stream);
+ outputSerializer.startDocument(null, true);
+ writeObserver.writeLocked(outputSerializer);
+ outputSerializer.endDocument();
+ testFile.finishWrite(stream);
+
+ // Read the observer
+ TypedXmlPullParser parser = Xml.resolvePullParser(testFile.openRead());
+ XmlUtils.beginDocument(parser, "observer");
+ ObserverInternal readObserver = ObserverInternal.read(parser, watchdog);
+
+ assertThat(readObserver.name).isEqualTo(writeObserver.name);
+ assertThat(readObserver.getBootMitigationCount()).isEqualTo(bootMitigationCount);
+ }
+
+ /**
+ * Ensure that boot mitigation counts may be correctly written and read as metadata
+ * in order to persist across reboots.
+ */
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testWritingAndReadingMetadataBootMitigationCountRecoverability() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ String filePath = InstrumentationRegistry.getContext().getFilesDir().toString()
+ + "metadata_file.txt";
+
+ ObserverInternal observer1 = new ObserverInternal("test1", List.of(), 1);
+ ObserverInternal observer2 = new ObserverInternal("test2", List.of(), 2);
+ watchdog.registerObserverInternal(observer1);
+ watchdog.registerObserverInternal(observer2);
+
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+
+ watchdog.saveAllObserversBootMitigationCountToMetadata(filePath);
+
+ observer1.setBootMitigationCount(0);
+ observer2.setBootMitigationCount(0);
+ assertThat(observer1.getBootMitigationCount()).isEqualTo(0);
+ assertThat(observer2.getBootMitigationCount()).isEqualTo(0);
+
+ mSpyBootThreshold.readAllObserversBootMitigationCountIfNecessary(filePath);
+
+ assertThat(observer1.getBootMitigationCount()).isEqualTo(1);
+ assertThat(observer2.getBootMitigationCount()).isEqualTo(2);
+ }
+
+ /**
* Tests device config changes are propagated correctly.
*/
@Test
@@ -1440,11 +1795,19 @@ public class PackageWatchdogTest {
// Mock CrashRecoveryProperties as they cannot be accessed due to SEPolicy restrictions
private void mockCrashRecoveryProperties(PackageWatchdog watchdog) {
+ mCrashRecoveryPropertiesMap = new HashMap<>();
+
try {
- mSpyBootThreshold = spy(watchdog.new BootThreshold(
- PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
- PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
- mCrashRecoveryPropertiesMap = new HashMap<>();
+ if (Flags.recoverabilityDetection()) {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+ } else {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+ }
doAnswer((Answer<Integer>) invocationOnMock -> {
String storedValue = mCrashRecoveryPropertiesMap
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index ba9e4a831789..f82d9ca13938 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -130,14 +130,13 @@ public class UpdatableSystemFontTest {
private static final Pattern PATTERN_SYSTEM_FONT_FILES =
Pattern.compile("^/(system|product)/fonts/");
- private String mKeyId;
private FontManager mFontManager;
private UiDevice mUiDevice;
@Before
public void setUp() throws Exception {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
- mKeyId = insertCert(CERT_PATH);
+ insertCert(CERT_PATH);
mFontManager = context.getSystemService(FontManager.class);
expectCommandToSucceed("cmd font clear");
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
@@ -147,9 +146,6 @@ public class UpdatableSystemFontTest {
public void tearDown() throws Exception {
// Ignore errors because this may fail if updatable system font is not enabled.
runShellCommand("cmd font clear", null);
- if (mKeyId != null) {
- expectCommandToSucceed("mini-keyctl unlink " + mKeyId + " .fs-verity");
- }
}
@Test
@@ -369,20 +365,11 @@ public class UpdatableSystemFontTest {
assertThat(isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID)).isFalse();
}
- private static String insertCert(String certPath) throws Exception {
- Pair<String, String> result;
- try (InputStream is = new FileInputStream(certPath)) {
- result = runShellCommand("mini-keyctl padd asymmetric fsv_test .fs-verity", is);
- }
+ private static void insertCert(String certPath) throws Exception {
// /data/local/tmp is not readable by system server. Copy a cert file to /data/fonts
final String copiedCert = "/data/fonts/debug_cert.der";
runShellCommand("cp " + certPath + " " + copiedCert, null);
runShellCommand("cmd font install-debug-cert " + copiedCert, null);
- // Assert that there are no errors.
- assertThat(result.second).isEmpty();
- String keyId = result.first.trim();
- assertThat(keyId).matches("^\\d+$");
- return keyId;
}
private int updateFontFile(String fontPath, String signaturePath) throws IOException {
diff --git a/tests/testables/OWNERS b/tests/testables/OWNERS
new file mode 100644
index 000000000000..a6f1632e7b8c
--- /dev/null
+++ b/tests/testables/OWNERS
@@ -0,0 +1 @@
+file:/packages/SystemUI/OWNERS \ No newline at end of file
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
index bc1df75bb142..ee2e7cfcd480 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -31,6 +31,7 @@ android_test {
"platform-test-annotations",
"services.core",
"service-connectivity-tiramisu-pre-jarjar",
+ "flag-junit",
],
libs: [
"android.test.runner",
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 34f884b94296..887630b03a8c 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -38,6 +38,7 @@ import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
@@ -58,6 +59,7 @@ import android.os.HandlerExecutor;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -71,7 +73,10 @@ import android.util.ArraySet;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.telephony.flags.Flags;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -128,6 +133,9 @@ public class TelephonySubscriptionTrackerTest {
TEST_SUBID_TO_CARRIER_CONFIG_MAP = Collections.unmodifiableMap(subIdToCarrierConfigMap);
}
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+
@NonNull private final Context mContext;
@NonNull private final TestLooper mTestLooper;
@NonNull private final Handler mHandler;
@@ -185,6 +193,7 @@ public class TelephonySubscriptionTrackerTest {
@Before
public void setUp() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_FIX_CRASH_ON_GETTING_CONFIG_WHEN_PHONE_IS_GONE);
doReturn(2).when(mTelephonyManager).getActiveModemCount();
mCallback = mock(TelephonySubscriptionTrackerCallback.class);
@@ -594,4 +603,14 @@ public class TelephonySubscriptionTrackerTest {
new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
snapshot.getAllSubIdsInGroup(TEST_PARCEL_UUID));
}
+
+ @Test
+ public void testCarrierConfigChangeWhenPhoneIsGoneShouldNotCrash() throws Exception {
+ doThrow(new IllegalStateException("Carrier config loader is not available."))
+ .when(mCarrierConfigManager)
+ .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1), any());
+
+ sendCarrierConfigChange(true /* hasValidSubscription */);
+ mTestLooper.dispatchAll();
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
index 1d7be2f4f039..fdf8fb8d3c41 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
@@ -34,6 +34,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -333,6 +334,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
public void testHandleLossRate_validationFail() throws Exception {
checkHandleLossRate(
22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */);
+ verify(mConnectivityManager).reportNetworkConnectivity(mNetwork, false);
}
@Test
@@ -416,4 +418,31 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
checkGetPacketLossRate(oldState, 20000, 14000, 4096, 19);
checkGetPacketLossRate(oldState, 20000, 14000, 3000, 10);
}
+
+ // Verify the polling event is scheduled with expected delays
+ private void verifyPollEventDelayAndScheduleNext(long expectedDelayMs) {
+ if (expectedDelayMs > 0) {
+ mTestLooper.dispatchAll();
+ verify(mIpSecTransform, never()).requestIpSecTransformState(any(), any());
+ mTestLooper.moveTimeForward(expectedDelayMs);
+ }
+
+ mTestLooper.dispatchAll();
+ verify(mIpSecTransform).requestIpSecTransformState(any(), any());
+ reset(mIpSecTransform);
+ }
+
+ @Test
+ public void testOnLinkPropertiesOrCapabilitiesChange() throws Exception {
+ // Start the monitor; verify the 1st poll is scheduled without delay
+ startMonitorAndCaptureStateReceiver();
+ verifyPollEventDelayAndScheduleNext(0 /* expectedDelayMs */);
+
+ // Verify the 2nd poll is rescheduled without delay
+ mIpSecPacketLossDetector.onLinkPropertiesOrCapabilitiesChanged();
+ verifyPollEventDelayAndScheduleNext(0 /* expectedDelayMs */);
+
+ // Verify the 3rd poll is scheduled with configured delay
+ verifyPollEventDelayAndScheduleNext(POLL_IPSEC_STATE_INTERVAL_MS);
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
index 381c57496878..af6daa17e223 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.IpSecConfig;
import android.net.IpSecTransform;
import android.net.LinkProperties;
@@ -33,12 +34,14 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.TelephonyNetworkSpecifier;
import android.net.vcn.FeatureFlags;
+import android.net.vcn.Flags;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.ParcelUuid;
import android.os.PowerManager;
import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.TelephonyManager;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -46,6 +49,7 @@ import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
import org.junit.Before;
+import org.junit.Rule;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -53,6 +57,8 @@ import java.util.Set;
import java.util.UUID;
public abstract class NetworkEvaluationTestBase {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
protected static final String SSID = "TestWifi";
protected static final String SSID_OTHER = "TestWifiOther";
protected static final String PLMN_ID = "123456";
@@ -103,6 +109,7 @@ public abstract class NetworkEvaluationTestBase {
@Mock protected FeatureFlags mFeatureFlags;
@Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags;
@Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot;
+ @Mock protected ConnectivityManager mConnectivityManager;
@Mock protected TelephonyManager mTelephonyManager;
@Mock protected IPowerManager mPowerManagerService;
@@ -114,6 +121,9 @@ public abstract class NetworkEvaluationTestBase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS);
+ mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE);
+
when(mNetwork.getNetId()).thenReturn(-1);
mTestLooper = new TestLooper();
@@ -130,6 +140,12 @@ public abstract class NetworkEvaluationTestBase {
doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled();
setupSystemService(
+ mContext,
+ mConnectivityManager,
+ Context.CONNECTIVITY_SERVICE,
+ ConnectivityManager.class);
+
+ setupSystemService(
mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID);
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
index aa81efe9a1ce..1d6872195e81 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
@@ -31,6 +31,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -333,4 +334,36 @@ public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase {
.compare(penalized, notPenalized);
assertEquals(1, result);
}
+
+ @Test
+ public void testNotifyNetworkMetricMonitorOnLpChange() throws Exception {
+ // Clear calls invoked when initializing mNetworkEvaluator
+ reset(mIpSecPacketLossDetector);
+
+ final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator();
+ evaluator.setNetworkCapabilities(
+ CELL_NETWORK_CAPABILITIES,
+ VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mCarrierConfig);
+
+ verify(mIpSecPacketLossDetector).onLinkPropertiesOrCapabilitiesChanged();
+ }
+
+ @Test
+ public void testNotifyNetworkMetricMonitorOnNcChange() throws Exception {
+ // Clear calls invoked when initializing mNetworkEvaluator
+ reset(mIpSecPacketLossDetector);
+
+ final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator();
+ evaluator.setLinkProperties(
+ LINK_PROPERTIES,
+ VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mCarrierConfig);
+
+ verify(mIpSecPacketLossDetector).onLinkPropertiesOrCapabilitiesChanged();
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index 70f56ae37a97..3e2b6518d678 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -1051,6 +1051,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 name Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1074,6 +1077,12 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
0 18 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
0 18 3 longName Ljava/lang/String;
0 18 4 shortName Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
RuntimeInvisibleAnnotations:
x: #x()
@@ -1224,6 +1233,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 name Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -1239,6 +1251,10 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
Signature: #x // ()V
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
@@ -2031,6 +2047,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex
Start Length Slot Name Signature
0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
0 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -2147,6 +2166,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex
Start Length Slot Name Signature
0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
0 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -2304,6 +2326,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
Start Length Slot Name Signature
0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
0 15 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeInvisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index b0db48347d46..ab7a05c9c85d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -795,6 +795,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -815,6 +818,12 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestStub
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
public java.lang.String getLongName();
descriptor: ()Ljava/lang/String;
@@ -969,6 +978,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -986,6 +998,10 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -1769,6 +1785,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index 112f69e43c69..dc3729c8f9ed 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -1225,6 +1225,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1257,6 +1260,12 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestStub
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
public java.lang.String getLongName();
descriptor: ()Ljava/lang/String;
@@ -1453,6 +1462,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -1474,6 +1486,10 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -2578,6 +2594,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -2745,6 +2764,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -2977,6 +2999,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index b0db48347d46..ab7a05c9c85d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -795,6 +795,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -815,6 +818,12 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestStub
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
public java.lang.String getLongName();
descriptor: ()Ljava/lang/String;
@@ -969,6 +978,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -986,6 +998,10 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -1769,6 +1785,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 2357844c1e10..0e0e8263b6cf 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -1532,6 +1532,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1569,6 +1572,12 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestStub
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
public java.lang.String getLongName();
descriptor: ()Ljava/lang/String;
@@ -1798,6 +1807,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -1824,6 +1836,10 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -3190,6 +3206,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -3407,6 +3426,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -3704,6 +3726,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses