Merge "Set is_stubs_module for stubs modules" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index c76be6f..d1afb86 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -19,14 +19,15 @@
     ":android.content.res.flags-aconfig-java{.generated_srcjars}",
     ":android.crashrecovery.flags-aconfig-java{.generated_srcjars}",
     ":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}",
+    ":android.media.codec-aconfig-java{.generated_srcjars}",
     ":android.media.playback.flags-aconfig-java{.generated_srcjars}",
+    ":android.net.platform.flags-aconfig-java{.generated_srcjars}",
     ":android.net.vcn.flags-aconfig-java{.generated_srcjars}",
     ":android.nfc.flags-aconfig-java{.generated_srcjars}",
     ":android.os.flags-aconfig-java{.generated_srcjars}",
     ":android.security.flags-aconfig-java{.generated_srcjars}",
     ":com.android.hardware.camera2-aconfig-java{.generated_srcjars}",
     ":com.android.hardware.input-aconfig-java{.generated_srcjars}",
-    ":com.android.net.flags-aconfig-java{.generated_srcjars}",
     ":com.android.net.thread.flags-aconfig-java{.generated_srcjars}",
     ":com.android.text.flags-aconfig-java{.generated_srcjars}",
     ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
@@ -41,6 +42,7 @@
         "android.crashrecovery.flags-aconfig",
         "android.hardware.biometrics.flags-aconfig",
         "android.media.playback.flags-aconfig",
+        "android.net.platform.flags-aconfig",
         "android.net.vcn.flags-aconfig",
         "android.nfc.flags-aconfig",
         "android.os.flags-aconfig",
@@ -50,7 +52,6 @@
         "com.android.net.thread.flags-aconfig",
         "com.android.window.flags.window-aconfig",
         "com.android.text.flags-aconfig",
-        "com.android.net.flags-aconfig",
     ],
 }
 
@@ -246,9 +247,10 @@
 
 // Networking
 aconfig_declarations {
-    name: "com.android.net.flags-aconfig",
-    package: "com.android.net.flags",
+    name: "android.net.platform.flags-aconfig",
+    package: "android.net.platform.flags",
     srcs: ["core/java/android/net/flags.aconfig"],
+    visibility: [":__subpackages__"],
 }
 
 // Thread network
@@ -259,9 +261,10 @@
 }
 
 java_aconfig_library {
-    name: "com.android.net.flags-aconfig-java",
-    aconfig_declarations: "com.android.net.flags-aconfig",
+    name: "android.net.platform.flags-aconfig-java",
+    aconfig_declarations: "android.net.platform.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
+    visibility: [":__subpackages__"],
 }
 
 java_aconfig_library {
diff --git a/api/Android.bp b/api/Android.bp
index 113424f..ea59d0b 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -208,7 +208,7 @@
     out: ["current.srcjar"],
     cmd: "$(location merge_zips) $(out) $(in)",
     srcs: [
-        ":api-stubs-docs-non-updatable",
+        ":api-stubs-docs-non-updatable{.exportable}",
         ":all-modules-public-stubs-source",
     ],
     visibility: ["//visibility:private"], // Used by make module in //development, mind
@@ -374,7 +374,10 @@
     previous_api: ":android.api.public.latest",
     merge_annotations_dirs: ["metalava-manual"],
     defaults_visibility: ["//frameworks/base/api"],
-    visibility: ["//frameworks/base/api"],
+    visibility: [
+        "//frameworks/base/api",
+        "//frameworks/base/core/api",
+    ],
 }
 
 // We resolve dependencies on APIs in modules by depending on a prebuilt of the whole
diff --git a/api/api.go b/api/api.go
index 3632fa8..b31a26c 100644
--- a/api/api.go
+++ b/api/api.go
@@ -79,7 +79,45 @@
 
 var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents)
 
+func (a *CombinedApis) apiFingerprintStubDeps() []string {
+	ret := []string{}
+	ret = append(
+		ret,
+		transformArray(a.properties.Bootclasspath, "", ".stubs")...,
+	)
+	ret = append(
+		ret,
+		transformArray(a.properties.Bootclasspath, "", ".stubs.system")...,
+	)
+	ret = append(
+		ret,
+		transformArray(a.properties.Bootclasspath, "", ".stubs.module_lib")...,
+	)
+	ret = append(
+		ret,
+		transformArray(a.properties.System_server_classpath, "", ".stubs.system_server")...,
+	)
+	return ret
+}
+
+func (a *CombinedApis) DepsMutator(ctx android.BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), nil, a.apiFingerprintStubDeps()...)
+}
+
 func (a *CombinedApis) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		if _, ok := child.(java.AndroidLibraryDependency); ok && child.Name() != "framework-res" {
+			// Stubs of BCP and SSCP libraries should not have any dependencies on apps
+			// This check ensures that we do not run into circular dependencies when UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT=true
+			ctx.ModuleErrorf(
+				"Module %s is not a valid dependency of the stub library %s\n."+
+					"If this dependency has been added via `libs` of java_sdk_library, please move it to `impl_only_libs`\n",
+				child.Name(), parent.Name())
+			return false // error detected
+		}
+		return true
+	})
+
 }
 
 type genruleProps struct {
@@ -131,7 +169,7 @@
 	Scope string
 }
 
-func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) {
+func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition, stubsTypeSuffix string, doDist bool) {
 	metalavaCmd := "$(location metalava)"
 	// Silence reflection warnings. See b/168689341
 	metalavaCmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
@@ -141,7 +179,7 @@
 	if txt.Scope != "public" {
 		filename = txt.Scope + "-" + filename
 	}
-	moduleName := ctx.ModuleName() + "-" + filename
+	moduleName := ctx.ModuleName() + stubsTypeSuffix + filename
 
 	props := genruleProps{}
 	props.Name = proptools.StringPtr(moduleName)
@@ -149,17 +187,19 @@
 	props.Out = []string{filename}
 	props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --out $(out)")
 	props.Srcs = append([]string{txt.BaseTxt}, createSrcs(txt.Modules, txt.ModuleTag)...)
-	props.Dists = []android.Dist{
-		{
-			Targets: []string{"droidcore"},
-			Dir:     proptools.StringPtr("api"),
-			Dest:    proptools.StringPtr(filename),
-		},
-		{
-			Targets: []string{"api_txt", "sdk"},
-			Dir:     proptools.StringPtr("apistubs/android/" + txt.Scope + "/api"),
-			Dest:    proptools.StringPtr(txt.DistFilename),
-		},
+	if doDist {
+		props.Dists = []android.Dist{
+			{
+				Targets: []string{"droidcore"},
+				Dir:     proptools.StringPtr("api"),
+				Dest:    proptools.StringPtr(filename),
+			},
+			{
+				Targets: []string{"api_txt", "sdk"},
+				Dir:     proptools.StringPtr("apistubs/android/" + txt.Scope + "/api"),
+				Dest:    proptools.StringPtr(txt.DistFilename),
+			},
+		}
 	}
 	props.Visibility = []string{"//visibility:public"}
 	ctx.CreateModule(genrule.GenRuleFactory, &props)
@@ -354,7 +394,7 @@
 	ctx.CreateModule(android.FileGroupFactory, &props)
 }
 
-func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string) {
+func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string, baseTxtModulePrefix, stubsTypeSuffix string, doDist bool) {
 	var textFiles []MergedTxtDefinition
 
 	tagSuffix := []string{".api.txt}", ".removed-api.txt}"}
@@ -363,7 +403,7 @@
 		textFiles = append(textFiles, MergedTxtDefinition{
 			TxtFilename:  f,
 			DistFilename: distFilename[i],
-			BaseTxt:      ":non-updatable-" + f,
+			BaseTxt:      ":" + baseTxtModulePrefix + f,
 			Modules:      bootclasspath,
 			ModuleTag:    "{.public" + tagSuffix[i],
 			Scope:        "public",
@@ -371,7 +411,7 @@
 		textFiles = append(textFiles, MergedTxtDefinition{
 			TxtFilename:  f,
 			DistFilename: distFilename[i],
-			BaseTxt:      ":non-updatable-system-" + f,
+			BaseTxt:      ":" + baseTxtModulePrefix + "system-" + f,
 			Modules:      bootclasspath,
 			ModuleTag:    "{.system" + tagSuffix[i],
 			Scope:        "system",
@@ -379,7 +419,7 @@
 		textFiles = append(textFiles, MergedTxtDefinition{
 			TxtFilename:  f,
 			DistFilename: distFilename[i],
-			BaseTxt:      ":non-updatable-module-lib-" + f,
+			BaseTxt:      ":" + baseTxtModulePrefix + "module-lib-" + f,
 			Modules:      bootclasspath,
 			ModuleTag:    "{.module-lib" + tagSuffix[i],
 			Scope:        "module-lib",
@@ -387,14 +427,14 @@
 		textFiles = append(textFiles, MergedTxtDefinition{
 			TxtFilename:  f,
 			DistFilename: distFilename[i],
-			BaseTxt:      ":non-updatable-system-server-" + f,
+			BaseTxt:      ":" + baseTxtModulePrefix + "system-server-" + f,
 			Modules:      system_server_classpath,
 			ModuleTag:    "{.system-server" + tagSuffix[i],
 			Scope:        "system-server",
 		})
 	}
 	for _, txt := range textFiles {
-		createMergedTxt(ctx, txt)
+		createMergedTxt(ctx, txt, stubsTypeSuffix, doDist)
 	}
 }
 
@@ -478,7 +518,8 @@
 		bootclasspath = append(bootclasspath, a.properties.Conditional_bootclasspath...)
 		sort.Strings(bootclasspath)
 	}
-	createMergedTxts(ctx, bootclasspath, system_server_classpath)
+	createMergedTxts(ctx, bootclasspath, system_server_classpath, "non-updatable-", "-", false)
+	createMergedTxts(ctx, bootclasspath, system_server_classpath, "non-updatable-exportable-", "-exportable-", true)
 
 	createMergedPublicStubs(ctx, bootclasspath)
 	createMergedSystemStubs(ctx, bootclasspath)
diff --git a/core/api/Android.bp b/core/api/Android.bp
index 8d8a82b..77594b7 100644
--- a/core/api/Android.bp
+++ b/core/api/Android.bp
@@ -96,3 +96,54 @@
     name: "non-updatable-test-lint-baseline.txt",
     srcs: ["test-lint-baseline.txt"],
 }
+
+// Exportable stub artifacts
+filegroup {
+    name: "non-updatable-exportable-current.txt",
+    srcs: [":api-stubs-docs-non-updatable{.exportable.api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-removed.txt",
+    srcs: [":api-stubs-docs-non-updatable{.exportable.removed-api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-system-current.txt",
+    srcs: [":system-api-stubs-docs-non-updatable{.exportable.api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-system-removed.txt",
+    srcs: [":system-api-stubs-docs-non-updatable{.exportable.removed-api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-module-lib-current.txt",
+    srcs: [":module-lib-api-stubs-docs-non-updatable{.exportable.api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-module-lib-removed.txt",
+    srcs: [":module-lib-api-stubs-docs-non-updatable{.exportable.removed-api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-test-current.txt",
+    srcs: [":test-api-stubs-docs-non-updatable{.exportable.api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-test-removed.txt",
+    srcs: [":test-api-stubs-docs-non-updatable{.exportable.removed-api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-system-server-current.txt",
+    srcs: [":services-non-updatable-stubs{.exportable.api.txt}"],
+}
+
+filegroup {
+    name: "non-updatable-exportable-system-server-removed.txt",
+    srcs: [":services-non-updatable-stubs{.exportable.removed-api.txt}"],
+}
diff --git a/core/api/current.txt b/core/api/current.txt
index ea1cd21d..b6a8681 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -22552,6 +22552,7 @@
     method @NonNull public static android.view.Surface createPersistentInputSurface();
     method public int dequeueInputBuffer(long);
     method public int dequeueOutputBuffer(@NonNull android.media.MediaCodec.BufferInfo, long);
+    method @FlaggedApi("android.media.codec.null_output_surface") public void detachOutputSurface();
     method protected void finalize();
     method public void flush();
     method @NonNull public String getCanonicalName();
@@ -22575,6 +22576,7 @@
     method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
     method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
     method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
+    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueSecureInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
     method public void release();
     method public void releaseOutputBuffer(int, boolean);
     method public void releaseOutputBuffer(int, long);
@@ -22599,6 +22601,7 @@
     field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
     field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8
     field @Deprecated public static final int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
+    field @FlaggedApi("android.media.codec.null_output_surface") public static final int CONFIGURE_FLAG_DETACHED_SURFACE = 8; // 0x8
     field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
     field public static final int CONFIGURE_FLAG_USE_BLOCK_MODEL = 2; // 0x2
     field public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4; // 0x4
@@ -22611,6 +22614,8 @@
     field public static final String PARAMETER_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
     field public static final String PARAMETER_KEY_LOW_LATENCY = "low-latency";
     field public static final String PARAMETER_KEY_OFFSET_TIME = "time-offset-us";
+    field @FlaggedApi("android.media.codec.region_of_interest") public static final String PARAMETER_KEY_QP_OFFSET_MAP = "qp-offset-map";
+    field @FlaggedApi("android.media.codec.region_of_interest") public static final String PARAMETER_KEY_QP_OFFSET_RECTS = "qp-offset-rects";
     field public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
     field public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
     field public static final String PARAMETER_KEY_SUSPEND_TIME = "drop-start-time-us";
@@ -22748,6 +22753,7 @@
     method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
     method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int);
     method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
+    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setMultiFrameEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
     method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
     method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
   }
@@ -22842,15 +22848,19 @@
     field @Deprecated public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
     field @Deprecated public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
     field public static final String FEATURE_AdaptivePlayback = "adaptive-playback";
+    field @FlaggedApi("android.media.codec.null_output_surface") public static final String FEATURE_DetachedSurface = "detached-surface";
+    field @FlaggedApi("android.media.codec.dynamic_color_aspects") public static final String FEATURE_DynamicColorAspects = "dynamic-color-aspects";
     field public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
     field public static final String FEATURE_EncodingStatistics = "encoding-statistics";
     field public static final String FEATURE_FrameParsing = "frame-parsing";
     field public static final String FEATURE_HdrEditing = "hdr-editing";
+    field @FlaggedApi("android.media.codec.hlg_editing") public static final String FEATURE_HlgEditing = "hlg-editing";
     field public static final String FEATURE_IntraRefresh = "intra-refresh";
     field public static final String FEATURE_LowLatency = "low-latency";
     field public static final String FEATURE_MultipleFrames = "multiple-frames";
     field public static final String FEATURE_PartialFrame = "partial-frame";
     field public static final String FEATURE_QpBounds = "qp-bounds";
+    field @FlaggedApi("android.media.codec.region_of_interest") public static final String FEATURE_Roi = "region-of-interest";
     field public static final String FEATURE_SecurePlayback = "secure-playback";
     field public static final String FEATURE_TunneledPlayback = "tunneled-playback";
     field public int[] colorFormats;
@@ -39158,7 +39168,7 @@
     method @Nullable public java.util.Date getKeyValidityStart();
     method @NonNull public String getKeystoreAlias();
     method public int getMaxUsageCount();
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
     method public int getPurposes();
     method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationType();
@@ -39166,7 +39176,7 @@
     method public boolean isDevicePropertiesAttestationIncluded();
     method @NonNull public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public boolean isMgf1DigestsSpecified();
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public boolean isMgf1DigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isStrongBoxBacked();
     method public boolean isUnlockedDeviceRequired();
@@ -39198,7 +39208,7 @@
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int);
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...);
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
@@ -39303,14 +39313,14 @@
     method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
     method @Nullable public java.util.Date getKeyValidityStart();
     method public int getMaxUsageCount();
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
     method public int getPurposes();
     method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationType();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public boolean isMgf1DigestsSpecified();
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public boolean isMgf1DigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUnlockedDeviceRequired();
     method public boolean isUserAuthenticationRequired();
@@ -39332,7 +39342,7 @@
     method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
     method @NonNull public android.security.keystore.KeyProtection.Builder setMaxUsageCount(int);
-    method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...);
+    method @FlaggedApi("android.security.mgf1_digest_setter_v2") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...);
     method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index cdeddfb..250a6ff 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3860,6 +3860,7 @@
     method public void setInstallAsInstantApp(boolean);
     method public void setInstallAsVirtualPreload();
     method public void setRequestDowngrade(boolean);
+    method @FlaggedApi("android.content.pm.recoverability_detection") @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void setRollbackImpactLevel(int);
     method @FlaggedApi("android.content.pm.rollback_lifetime") @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void setRollbackLifetimeMillis(long);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
   }
@@ -4023,6 +4024,9 @@
     field public static final int ROLLBACK_DATA_POLICY_RESTORE = 0; // 0x0
     field public static final int ROLLBACK_DATA_POLICY_RETAIN = 2; // 0x2
     field public static final int ROLLBACK_DATA_POLICY_WIPE = 1; // 0x1
+    field @FlaggedApi("android.content.pm.recoverability_detection") public static final int ROLLBACK_USER_IMPACT_HIGH = 1; // 0x1
+    field @FlaggedApi("android.content.pm.recoverability_detection") public static final int ROLLBACK_USER_IMPACT_LOW = 0; // 0x0
+    field @FlaggedApi("android.content.pm.recoverability_detection") public static final int ROLLBACK_USER_IMPACT_ONLY_MANUAL = 2; // 0x2
     field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; // 0x0
     field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; // 0x1
     field public static final int SYSTEM_APP_STATE_INSTALLED = 2; // 0x2
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4402576..32b031b 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1148,6 +1148,10 @@
 
 package android.content.rollback {
 
+  public final class RollbackInfo implements android.os.Parcelable {
+    method @FlaggedApi("android.content.pm.recoverability_detection") public int getRollbackImpactLevel();
+  }
+
   public final class RollbackManager {
     method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void blockRollbackManager(long);
     method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
@@ -1630,6 +1634,7 @@
     method @NonNull public java.util.List<java.lang.String> getKeyboardLayoutDescriptorsForInputDevice(@NonNull android.view.InputDevice);
     method @NonNull public String getKeyboardLayoutTypeForLayoutDescriptor(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public java.util.Map<java.lang.Integer,java.lang.Integer> getModifierKeyRemapping();
+    method public int getMousePointerSpeed();
     method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void remapModifierKey(int, int);
     method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void removeKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
     method public void removeUniqueIdAssociation(@NonNull String);
@@ -1639,6 +1644,7 @@
 
   public class InputSettings {
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void setMaximumObscuringOpacityForTouch(@NonNull android.content.Context, @FloatRange(from=0, to=1) float);
+    field public static final int DEFAULT_POINTER_SPEED = 0; // 0x0
   }
 
 }
@@ -2790,6 +2796,10 @@
     field public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
   }
 
+  public static final class Settings.System extends android.provider.Settings.NameValueTable {
+    field public static final String POINTER_SPEED = "pointer_speed";
+  }
+
   public static final class Telephony.Sms.Intents {
     field public static final String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
   }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ccd83f7..667d3e6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -4338,19 +4338,19 @@
          */
         private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
                 @UidState int toUidState, @OpFlags int flags) {
-            NoteOpEvent lastAccessEvent = null;
+            NoteOpEvent lastRejectEvent = null;
             for (AttributedOpEntry attributionEntry : mAttributedOpEntries.values()) {
-                NoteOpEvent lastAttributionAccessEvent = attributionEntry.getLastRejectEvent(
+                NoteOpEvent lastAttributionRejectEvent = attributionEntry.getLastRejectEvent(
                         fromUidState, toUidState, flags);
 
-                if (lastAccessEvent == null || (lastAttributionAccessEvent != null
-                        && lastAttributionAccessEvent.getNoteTime()
-                        > lastAccessEvent.getNoteTime())) {
-                    lastAccessEvent = lastAttributionAccessEvent;
+                if (lastRejectEvent == null || (lastAttributionRejectEvent != null
+                        && lastAttributionRejectEvent.getNoteTime()
+                        > lastRejectEvent.getNoteTime())) {
+                    lastRejectEvent = lastAttributionRejectEvent;
                 }
             }
 
-            return lastAccessEvent;
+            return lastRejectEvent;
         }
 
         /**
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index d859f3f..17177ff 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -460,6 +460,15 @@
      */
     public static final int SUBREASON_SDK_SANDBOX_NOT_NEEDED = 28;
 
+    /**
+     * The process was killed by the [kernel] Out-of-memory (OOM) killer; this
+     * would be set only when the reason is {@link #REASON_LOW_MEMORY}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_OOM_KILL = 30;
+
     // If there is any OEM code which involves additional app kill reasons, it should
     // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
 
@@ -635,6 +644,7 @@
         SUBREASON_KILL_BACKGROUND,
         SUBREASON_PACKAGE_UPDATE,
         SUBREASON_UNDELIVERED_BROADCAST,
+        SUBREASON_OOM_KILL,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SubReason {}
@@ -1360,6 +1370,8 @@
                 return "PACKAGE UPDATE";
             case SUBREASON_UNDELIVERED_BROADCAST:
                 return "UNDELIVERED BROADCAST";
+            case SUBREASON_OOM_KILL:
+                return "OOM KILL";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 41d7932..19b91ed 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -31,6 +31,7 @@
 per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS
 per-file *UiAutomation* = file:/services/accessibility/OWNERS
+per-file *UiAutomation* = file:/core/java/android/permission/OWNERS
 per-file GameManager* = file:/GAME_MANAGER_OWNERS
 per-file GameMode* = file:/GAME_MANAGER_OWNERS
 per-file GameState* = file:/GAME_MANAGER_OWNERS
diff --git a/core/java/android/app/ondeviceintelligence/OWNERS b/core/java/android/app/ondeviceintelligence/OWNERS
new file mode 100644
index 0000000..6932ba2
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 1363385
+
+sandeepbandaru@google.com
+shivanker@google.com
+hackz@google.com
+volnov@google.com
+
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index f946754..01ea4e9 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -664,7 +664,7 @@
      * has at least one HTTP or HTTPS data URI pattern defined, and optionally
      * does not define any non-http/https data URI patterns.
      *
-     * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
+     * This will check if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
      * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
      * data scheme is "http" or "https".
      *
@@ -705,7 +705,7 @@
         }
 
         // We get here if:
-        //   1) onlyWebSchemes and no non-web schemes were found, i.e success; or
+        //   1) onlyWebSchemes and no non-web schemes were found, i.e. success; or
         //   2) !onlyWebSchemes and no http/https schemes were found, i.e. failure.
         return onlyWebSchemes;
     }
@@ -715,7 +715,7 @@
      *
      * @return True if the filter needs to be automatically verified. False otherwise.
      *
-     * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
+     * This will check if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
      * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
      * data scheme is "http" or "https".
      *
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
index 5bdcc1c..d7a0cbd 100644
--- a/core/java/android/content/pm/OWNERS
+++ b/core/java/android/content/pm/OWNERS
@@ -3,10 +3,20 @@
 file:/PACKAGE_MANAGER_OWNERS
 
 per-file PackageParser.java = set noparent
-per-file PackageParser.java = chiuwinson@google.com,patb@google.com
+per-file PackageParser.java = file:/PACKAGE_MANAGER_OWNERS
+
+# Bug component: 166829 = per-file *Capability*
 per-file *Capability* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+# Bug component: 166829 = per-file *Shortcut*
 per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+
+# Bug component: 860423 = per-file *Launcher*
 per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
+
+# Bug component: 578329 = per-file *UserInfo*
 per-file UserInfo* = file:/MULTIUSER_OWNERS
+# Bug component: 578329 = per-file *UserProperties*
 per-file *UserProperties* = file:/MULTIUSER_OWNERS
-per-file IBackgroundInstallControlService.aidl = file:/services/core/java/com/android/server/pm/BACKGROUND_INSTALL_OWNERS
\ No newline at end of file
+
+# Bug component: 1219020 = per-file *BackgroundInstallControl*
+per-file *BackgroundInstallControl* = file:/services/core/java/com/android/server/pm/BACKGROUND_INSTALL_OWNERS
\ No newline at end of file
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 920cc57..6ca6194 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2374,6 +2374,8 @@
         /** @hide */
         public long rollbackLifetimeMillis = 0;
         /** {@hide} */
+        public int rollbackImpactLevel = PackageManager.ROLLBACK_USER_IMPACT_LOW;
+        /** {@hide} */
         public boolean forceQueryableOverride;
         /** {@hide} */
         public int requireUserAction = USER_ACTION_UNSPECIFIED;
@@ -2428,6 +2430,7 @@
             }
             rollbackDataPolicy = source.readInt();
             rollbackLifetimeMillis = source.readLong();
+            rollbackImpactLevel = source.readInt();
             requireUserAction = source.readInt();
             packageSource = source.readInt();
             applicationEnabledSettingPersistent = source.readBoolean();
@@ -2461,6 +2464,7 @@
             ret.dataLoaderParams = dataLoaderParams;
             ret.rollbackDataPolicy = rollbackDataPolicy;
             ret.rollbackLifetimeMillis = rollbackLifetimeMillis;
+            ret.rollbackImpactLevel = rollbackImpactLevel;
             ret.requireUserAction = requireUserAction;
             ret.packageSource = packageSource;
             ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
@@ -2772,13 +2776,14 @@
         }
 
         /**
-         * If rollback enabled for this session (via {@link #setEnableRollback}, set time
-         * after which rollback will no longer be possible
+         * If rollback enabled for this session (via {@link #setEnableRollback}, set period
+         * after which rollback files will be deleted due to expiration
+         * {@link RollbackManagerServiceImpl#deleteRollback}.
          *
          * <p>For multi-package installs, this value must be set on the parent session.
          * Child session rollback lifetime will be ignored.
          *
-         * @param lifetimeMillis time after which rollback expires
+         * @param lifetimeMillis period after which rollback expires
          * @throws IllegalArgumentException if lifetimeMillis is negative or rollback is not
          * enabled via setEnableRollback.
          * @hide
@@ -2798,6 +2803,28 @@
         }
 
         /**
+         * rollbackImpactLevel is a measure of impact a rollback has on the user. This can take one
+         * of 3 values:
+         * <ul>
+         *     <li>{@link PackageManager#ROLLBACK_USER_IMPACT_LOW} (default)</li>
+         *     <li>{@link PackageManager#ROLLBACK_USER_IMPACT_HIGH} (1)</li>
+         *     <li>{@link PackageManager#ROLLBACK_USER_IMPACT_ONLY_MANUAL} (2)</li>
+         * </ul>
+         *
+         * @hide
+         */
+        @SystemApi
+        @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+        @FlaggedApi(Flags.FLAG_RECOVERABILITY_DETECTION)
+        public void setRollbackImpactLevel(@PackageManager.RollbackImpactLevel int impactLevel) {
+            if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
+                throw new IllegalArgumentException(
+                        "Can't set rollbackImpactLevel when rollback is not enabled");
+            }
+            rollbackImpactLevel = impactLevel;
+        }
+
+        /**
          * @deprecated use {@link #setRequestDowngrade(boolean)}.
          * {@hide}
          */
@@ -3151,6 +3178,7 @@
             pw.printPair("dataLoaderParams", dataLoaderParams);
             pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
             pw.printPair("rollbackLifetimeMillis", rollbackLifetimeMillis);
+            pw.printPair("rollbackImpactLevel", rollbackImpactLevel);
             pw.printPair("applicationEnabledSettingPersistent",
                     applicationEnabledSettingPersistent);
             pw.printHexPair("developmentInstallFlags", developmentInstallFlags);
@@ -3193,6 +3221,7 @@
             }
             dest.writeInt(rollbackDataPolicy);
             dest.writeLong(rollbackLifetimeMillis);
+            dest.writeInt(rollbackImpactLevel);
             dest.writeInt(requireUserAction);
             dest.writeInt(packageSource);
             dest.writeBoolean(applicationEnabledSettingPersistent);
@@ -3390,6 +3419,9 @@
         public long rollbackLifetimeMillis;
 
         /** {@hide} */
+        public int rollbackImpactLevel;
+
+        /** {@hide} */
         public int requireUserAction;
 
         /** {@hide} */
@@ -3457,6 +3489,7 @@
             isPreapprovalRequested = source.readBoolean();
             rollbackDataPolicy = source.readInt();
             rollbackLifetimeMillis = source.readLong();
+            rollbackImpactLevel = source.readInt();
             createdMillis = source.readLong();
             requireUserAction = source.readInt();
             installerUid = source.readInt();
@@ -4081,6 +4114,7 @@
             dest.writeBoolean(isPreapprovalRequested);
             dest.writeInt(rollbackDataPolicy);
             dest.writeLong(rollbackLifetimeMillis);
+            dest.writeInt(rollbackImpactLevel);
             dest.writeLong(createdMillis);
             dest.writeInt(requireUserAction);
             dest.writeInt(installerUid);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1bc0418..6b156cf 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1429,6 +1429,44 @@
     public static final int ROLLBACK_DATA_POLICY_RETAIN = 2;
 
     /** @hide */
+    @IntDef(prefix = {"ROLLBACK_USER_IMPACT_"}, value = {
+            ROLLBACK_USER_IMPACT_LOW,
+            ROLLBACK_USER_IMPACT_HIGH,
+            ROLLBACK_USER_IMPACT_ONLY_MANUAL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RollbackImpactLevel {}
+
+    /**
+     * Rollback will be performed automatically in response to native crashes on startup or
+     * persistent service crashes. More suitable for apps that do not store any user data.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.content.pm.Flags.FLAG_RECOVERABILITY_DETECTION)
+    public static final int ROLLBACK_USER_IMPACT_LOW = 0;
+
+    /**
+     * Rollback will be performed automatically only when the device is found to be unrecoverable.
+     * More suitable for apps that store user data and have higher impact on user.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.content.pm.Flags.FLAG_RECOVERABILITY_DETECTION)
+    public static final int ROLLBACK_USER_IMPACT_HIGH = 1;
+
+    /**
+     * Rollback will not be performed automatically. It can be triggered externally.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.content.pm.Flags.FLAG_RECOVERABILITY_DETECTION)
+    public static final int ROLLBACK_USER_IMPACT_ONLY_MANUAL = 2;
+
+    /** @hide */
     @IntDef(flag = true, prefix = { "INSTALL_" }, value = {
             INSTALL_REPLACE_EXISTING,
             INSTALL_ALLOW_TEST,
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index d07de72..ab8fd5e 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -14,3 +14,11 @@
     bug: "299670324"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "recoverability_detection"
+    namespace: "package_manager_service"
+    description: "Feature flag to enable recoverability detection feature. It includes GMS core rollback and improvements to rescue party."
+    bug: "291135724"
+    is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index a363718..d128055 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -16,8 +16,12 @@
 
 package android.content.rollback;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.pm.Flags;
+import android.content.pm.PackageManager;
 import android.content.pm.VersionedPackage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -25,17 +29,14 @@
 import java.util.List;
 
 /**
- * Information about a set of packages that can be, or already have been
- * rolled back together.
+ * Information about a set of packages that can be, or already have been rolled back together.
  *
  * @hide
  */
 @SystemApi
 public final class RollbackInfo implements Parcelable {
 
-    /**
-     * A unique identifier for the rollback.
-     */
+    /** A unique identifier for the rollback. */
     private final int mRollbackId;
 
     private final List<PackageRollbackInfo> mPackages;
@@ -44,15 +45,39 @@
 
     private final boolean mIsStaged;
     private int mCommittedSessionId;
+    private int mRollbackImpactLevel;
 
     /** @hide */
-    public RollbackInfo(int rollbackId, List<PackageRollbackInfo> packages, boolean isStaged,
-            List<VersionedPackage> causePackages,  int committedSessionId) {
+    public RollbackInfo(
+            int rollbackId,
+            List<PackageRollbackInfo> packages,
+            boolean isStaged,
+            List<VersionedPackage> causePackages,
+            int committedSessionId,
+            @PackageManager.RollbackImpactLevel int rollbackImpactLevel) {
         this.mRollbackId = rollbackId;
         this.mPackages = packages;
         this.mIsStaged = isStaged;
         this.mCausePackages = causePackages;
         this.mCommittedSessionId = committedSessionId;
+        this.mRollbackImpactLevel = rollbackImpactLevel;
+    }
+
+    /** @hide */
+    public RollbackInfo(
+            int rollbackId,
+            List<PackageRollbackInfo> packages,
+            boolean isStaged,
+            List<VersionedPackage> causePackages,
+            int committedSessionId) {
+        // If impact level is not set default to 0
+        this(
+                rollbackId,
+                packages,
+                isStaged,
+                causePackages,
+                committedSessionId,
+                PackageManager.ROLLBACK_USER_IMPACT_LOW);
     }
 
     private RollbackInfo(Parcel in) {
@@ -61,34 +86,28 @@
         mIsStaged = in.readBoolean();
         mCausePackages = in.createTypedArrayList(VersionedPackage.CREATOR);
         mCommittedSessionId = in.readInt();
+        mRollbackImpactLevel = in.readInt();
     }
 
-    /**
-     * Returns a unique identifier for this rollback.
-     */
+    /** Returns a unique identifier for this rollback. */
     public int getRollbackId() {
         return mRollbackId;
     }
 
-    /**
-     * Returns the list of package that are rolled back.
-     */
+    /** Returns the list of package that are rolled back. */
     @NonNull
     public List<PackageRollbackInfo> getPackages() {
         return mPackages;
     }
 
-    /**
-     * Returns true if this rollback requires reboot to take effect after
-     * being committed.
-     */
+    /** Returns true if this rollback requires reboot to take effect after being committed. */
     public boolean isStaged() {
         return mIsStaged;
     }
 
     /**
-     * Returns the session ID for the committed rollback for staged rollbacks.
-     * Only applicable for rollbacks that have been committed.
+     * Returns the session ID for the committed rollback for staged rollbacks. Only applicable for
+     * rollbacks that have been committed.
      */
     public int getCommittedSessionId() {
         return mCommittedSessionId;
@@ -96,6 +115,7 @@
 
     /**
      * Sets the session ID for the committed rollback for staged rollbacks.
+     *
      * @hide
      */
     public void setCommittedSessionId(int sessionId) {
@@ -103,15 +123,40 @@
     }
 
     /**
-     * Gets the list of package versions that motivated this rollback.
-     * As provided to {@link #commitRollback} when the rollback was committed.
-     * This is only applicable for rollbacks that have been committed.
+     * Gets the list of package versions that motivated this rollback. As provided to {@link
+     * #commitRollback} when the rollback was committed. This is only applicable for rollbacks that
+     * have been committed.
      */
     @NonNull
     public List<VersionedPackage> getCausePackages() {
         return mCausePackages;
     }
 
+    /**
+     * Get rollback impact level. Refer {@link
+     * android.content.pm.PackageInstaller.SessionParams#setRollbackImpactLevel(int)} for more info
+     * on impact level.
+     *
+     * @hide
+     */
+    @TestApi
+    @FlaggedApi(Flags.FLAG_RECOVERABILITY_DETECTION)
+    public @PackageManager.RollbackImpactLevel int getRollbackImpactLevel() {
+        return mRollbackImpactLevel;
+    }
+
+    /**
+     * Set rollback impact level. Refer {@link
+     * android.content.pm.PackageInstaller.SessionParams#setRollbackImpactLevel(int)} for more info
+     * on impact level.
+     *
+     * @hide
+     */
+    public void setRollbackImpactLevel(
+            @PackageManager.RollbackImpactLevel int rollbackImpactLevel) {
+        mRollbackImpactLevel = rollbackImpactLevel;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -124,16 +169,17 @@
         out.writeBoolean(mIsStaged);
         out.writeTypedList(mCausePackages);
         out.writeInt(mCommittedSessionId);
+        out.writeInt(mRollbackImpactLevel);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<RollbackInfo> CREATOR =
             new Parcelable.Creator<RollbackInfo>() {
-        public RollbackInfo createFromParcel(Parcel in) {
-            return new RollbackInfo(in);
-        }
+                public RollbackInfo createFromParcel(Parcel in) {
+                    return new RollbackInfo(in);
+                }
 
-        public RollbackInfo[] newArray(int size) {
-            return new RollbackInfo[size];
-        }
-    };
+                public RollbackInfo[] newArray(int size) {
+                    return new RollbackInfo[size];
+                }
+            };
 }
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index c3fae55..059e99f 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -63,6 +63,9 @@
     // active keyboard layout.
     int getKeyCodeForKeyLocation(int deviceId, in int locationKeyCode);
 
+    // Returns the mouse pointer speed.
+    int getMousePointerSpeed();
+
     // Temporarily changes the pointer speed.
     void tryPointerSpeed(int speed);
 
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index a0cceae..08fc5c2 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -24,6 +24,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
@@ -835,6 +836,28 @@
     }
 
     /**
+     * Returns the mouse pointer speed.
+     *
+     * <p>The pointer speed is a value between {@link InputSettings#MIN_POINTER_SPEED} and
+     * {@link InputSettings#MAX_POINTER_SPEED}, the default value being
+     * {@link InputSettings#DEFAULT_POINTER_SPEED}.
+     *
+     * <p> Note that while setting the mouse pointer speed, it's possible that the input reader has
+     * only received this value and has not yet completed reconfiguring itself with this value.
+     *
+     * @hide
+     */
+    @SuppressLint("UnflaggedApi") // TestApi without associated feature.
+    @TestApi
+    public int getMousePointerSpeed() {
+        try {
+            return mIm.getMousePointerSpeed();
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Changes the mouse pointer speed temporarily, but does not save the setting.
      * <p>
      * Requires {@link android.Manifest.permission#SET_POINTER_SPEED}.
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 33960c0..042b0b7 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -48,8 +48,8 @@
 
     /**
      * Pointer Speed: The default pointer speed (0).
-     * @hide
      */
+    @SuppressLint("UnflaggedApi") // TestApi without associated feature.
     public static final int DEFAULT_POINTER_SPEED = 0;
 
     /**
diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig
index 0ad1804..311dc09 100644
--- a/core/java/android/net/flags.aconfig
+++ b/core/java/android/net/flags.aconfig
@@ -1,50 +1,11 @@
-package: "com.android.net.flags"
+package: "android.net.platform.flags"
 
-flag {
-  name: "track_multiple_network_activities"
-  namespace: "android_core_networking"
-  description: "NetworkActivityTracker tracks multiple networks including non default networks"
-  bug: "267870186"
-}
-
-flag {
-  name: "forbidden_capability"
-  namespace: "android_core_networking"
-  description: "This flag controls the forbidden capability API"
-  bug: "302997505"
-}
-
-flag {
-  name: "set_data_saver_via_cm"
-  namespace: "android_core_networking"
-  description: "Set data saver through ConnectivityManager API"
-  bug: "297836825"
-}
-
-flag {
-  name: "support_is_uid_networking_blocked"
-  namespace: "android_core_networking"
-  description: "This flag controls whether isUidNetworkingBlocked is supported"
-  bug: "297836825"
-}
-
-flag {
-  name: "basic_background_restrictions_enabled"
-  namespace: "android_core_networking"
-  description: "Block network access for apps in a low importance background state"
-  bug: "304347838"
-}
-
-flag {
-  name: "register_nsd_offload_engine"
-  namespace: "android_core_networking"
-  description: "The flag controls the access for registerOffloadEngine API in NsdManager"
-  bug: "294777050"
-}
+# This file contains aconfig flags used from platform code
+# Flags used for module APIs must be in aconfig files under each modules
 
 flag {
   name: "ipsec_transform_state"
-  namespace: "android_core_networking_ipsec"
+  namespace: "core_networking_ipsec"
   description: "The flag controls the access for getIpSecTransformState and IpSecTransformState"
   bug: "308011229"
 }
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 2145c1a..19a3ba0 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -95,3 +95,6 @@
 # SystemConfig
 per-file ISystemConfig.aidl = file:/PACKAGE_MANAGER_OWNERS
 per-file SystemConfigManager.java = file:/PACKAGE_MANAGER_OWNERS
+
+# ProfilingService
+per-file ProfilingServiceManager.java = file:/PERFORMANCE_OWNERS
diff --git a/core/java/android/os/OomKillRecord.java b/core/java/android/os/OomKillRecord.java
new file mode 100644
index 0000000..151a65f
--- /dev/null
+++ b/core/java/android/os/OomKillRecord.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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.os;
+
+
+/**
+ * Expected data to get back from the OOM event's file.
+ * Note that this should be equivalent to the struct <b>OomKill</b> inside
+ * <pre>
+ * system/memory/libmeminfo/libmemevents/include/memevents.h
+ * </pre>
+ *
+ * @hide
+ */
+public final class OomKillRecord {
+    private long mTimeStampInMillis;
+    private int mPid;
+    private int mUid;
+    private String mProcessName;
+    private short mOomScoreAdj;
+
+    public OomKillRecord(long timeStampInMillis, int pid, int uid,
+                            String processName, short oomScoreAdj) {
+        this.mTimeStampInMillis = timeStampInMillis;
+        this.mPid = pid;
+        this.mUid = uid;
+        this.mProcessName = processName;
+        this.mOomScoreAdj = oomScoreAdj;
+    }
+
+    public long getTimestampMilli() {
+        return mTimeStampInMillis;
+    }
+
+    public int getPid() {
+        return mPid;
+    }
+
+    public int getUid() {
+        return mUid;
+    }
+
+    public String getProcessName() {
+        return mProcessName;
+    }
+
+    public short getOomScoreAdj() {
+        return mOomScoreAdj;
+    }
+}
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index bf22dcc..5e0a563 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -10,7 +10,6 @@
 krishang@google.com
 riyaghai@google.com
 sahanas@google.com
-sergeynv@google.com
 shikhamalhotra@google.com
 shubhisaxena@google.com
 tylersaunders@google.com
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7bad9c5..82d33a9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5651,8 +5651,10 @@
          *   +7 = fastest
          * @hide
          */
+        @SuppressLint({"NoSettingsProvider", "UnflaggedApi"}) // TestApi without associated feature.
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         @Readable
+        @TestApi
         public static final String POINTER_SPEED = "pointer_speed";
 
         /**
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 43163b3..7631454 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -15,10 +15,11 @@
 }
 
 flag {
-    name: "mgf1_digest_setter"
+    name: "mgf1_digest_setter_v2"
     namespace: "hardware_backed_security"
     description: "Feature flag for mgf1 digest setter in key generation and import parameters."
     bug: "308378912"
+    is_fixed_read_only: true
 }
 
 flag {
diff --git a/core/java/android/service/ondeviceintelligence/OWNERS b/core/java/android/service/ondeviceintelligence/OWNERS
new file mode 100644
index 0000000..09774f7
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/ondeviceintelligence/OWNERS
diff --git a/core/java/android/service/voice/OWNERS b/core/java/android/service/voice/OWNERS
index ec44100..763c79e 100644
--- a/core/java/android/service/voice/OWNERS
+++ b/core/java/android/service/voice/OWNERS
@@ -4,4 +4,4 @@
 
 # The owner here should not be assist owner
 liangyuchen@google.com
-tuanng@google.com
+adudani@google.com
diff --git a/core/java/android/tracing/OWNERS b/core/java/android/tracing/OWNERS
index 2ebe2e9..f67844d 100644
--- a/core/java/android/tracing/OWNERS
+++ b/core/java/android/tracing/OWNERS
@@ -1,6 +1,4 @@
 carmenjackson@google.com
 kevinjeon@google.com
-pablogamito@google.com
-natanieljr@google.com
-keanmariotti@google.com
+include platform/development:/tools/winscope/OWNERS
 include platform/external/perfetto:/OWNERS
diff --git a/core/java/com/android/internal/protolog/OWNERS b/core/java/com/android/internal/protolog/OWNERS
new file mode 100644
index 0000000..18cf2be
--- /dev/null
+++ b/core/java/com/android/internal/protolog/OWNERS
@@ -0,0 +1,3 @@
+# ProtoLog owners
+# Bug component: 1157642
+include platform/development:/tools/winscope/OWNERS
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index ce4a337..8dc9d0a 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -39,6 +39,7 @@
 using vintf::HalManifest;
 using vintf::Level;
 using vintf::SchemaType;
+using vintf::SepolicyVersion;
 using vintf::to_string;
 using vintf::toXml;
 using vintf::Version;
@@ -139,7 +140,7 @@
         return nullptr;
     }
 
-    Version latest;
+    SepolicyVersion latest;
     for (const auto& range : versions) {
         latest = std::max(latest, range.maxVer());
     }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 9c40a28..2a2e903 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -665,8 +665,9 @@
   }
 }
 
-static void DropCapabilitiesBoundingSet(fail_fn_t fail_fn) {
+static void DropCapabilitiesBoundingSet(fail_fn_t fail_fn, jlong bounding_capabilities) {
   for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {;
+    if ((1LL << i) & bounding_capabilities) continue;
     if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) {
       if (errno == EINVAL) {
         ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
@@ -678,6 +679,27 @@
   }
 }
 
+static bool MatchGid(JNIEnv* env, jintArray gids, jint gid, jint gid_to_find) {
+  if (gid == gid_to_find) return true;
+
+  if (gids == nullptr) return false;
+
+  jsize gids_num = env->GetArrayLength(gids);
+  ScopedIntArrayRO native_gid_proxy(env, gids);
+
+  if (native_gid_proxy.get() == nullptr) {
+    RuntimeAbort(env, __LINE__, "Bad gids array");
+  }
+
+  for (int gids_index = 0; gids_index < gids_num; ++gids_index) {
+    if (native_gid_proxy[gids_index] == gid_to_find) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 static void SetInheritable(uint64_t inheritable, fail_fn_t fail_fn) {
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
@@ -1742,9 +1764,9 @@
 // Utility routine to specialize a zygote child process.
 static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags,
                              jobjectArray rlimits, jlong permitted_capabilities,
-                             jlong effective_capabilities, jint mount_external,
-                             jstring managed_se_info, jstring managed_nice_name,
-                             bool is_system_server, bool is_child_zygote,
+                             jlong effective_capabilities, jlong bounding_capabilities,
+                             jint mount_external, jstring managed_se_info,
+                             jstring managed_nice_name, bool is_system_server, bool is_child_zygote,
                              jstring managed_instruction_set, jstring managed_app_data_dir,
                              bool is_top_app, jobjectArray pkg_data_info_list,
                              jobjectArray allowlisted_data_info_list, bool mount_data_dirs,
@@ -1758,6 +1780,9 @@
     auto instruction_set = extract_fn(managed_instruction_set);
     auto app_data_dir = extract_fn(managed_app_data_dir);
 
+    // Permit bounding capabilities
+    permitted_capabilities |= bounding_capabilities;
+
     // Keep capabilities across UID change, unless we're staying root.
     if (uid != 0) {
         EnableKeepCapabilities(fail_fn);
@@ -1765,7 +1790,7 @@
 
     SetInheritable(permitted_capabilities, fail_fn);
 
-    DropCapabilitiesBoundingSet(fail_fn);
+    DropCapabilitiesBoundingSet(fail_fn, bounding_capabilities);
 
     bool need_pre_initialize_native_bridge = !is_system_server && instruction_set.has_value() &&
             android::NativeBridgeAvailable() &&
@@ -2028,6 +2053,23 @@
     return capdata[0].effective | (static_cast<uint64_t>(capdata[1].effective) << 32);
 }
 
+static jlong CalculateBoundingCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gids) {
+    jlong capabilities = 0;
+
+    /*
+     * Grant CAP_SYS_NICE to CapInh/CapPrm/CapBnd for processes that can spawn
+     * VMs.  This enables processes to execve on binaries with elevated
+     * capabilities if its file capability bits are set. This does not grant
+     * capability to the parent process(that spawns the VM) as the effective
+     * bits are not set.
+     */
+    if (MatchGid(env, gids, gid, AID_VIRTUALMACHINE)) {
+        capabilities |= (1LL << CAP_SYS_NICE);
+    }
+
+    return capabilities;
+}
+
 static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gids,
                                    bool is_child_zygote) {
   jlong capabilities = 0;
@@ -2061,26 +2103,7 @@
    * Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
    */
 
-  bool gid_wakelock_found = false;
-  if (gid == AID_WAKELOCK) {
-    gid_wakelock_found = true;
-  } else if (gids != nullptr) {
-    jsize gids_num = env->GetArrayLength(gids);
-    ScopedIntArrayRO native_gid_proxy(env, gids);
-
-    if (native_gid_proxy.get() == nullptr) {
-      RuntimeAbort(env, __LINE__, "Bad gids array");
-    }
-
-    for (int gids_index = 0; gids_index < gids_num; ++gids_index) {
-      if (native_gid_proxy[gids_index] == AID_WAKELOCK) {
-        gid_wakelock_found = true;
-        break;
-      }
-    }
-  }
-
-  if (gid_wakelock_found) {
+  if (MatchGid(env, gids, gid, AID_WAKELOCK)) {
     capabilities |= (1LL << CAP_BLOCK_SUSPEND);
   }
 
@@ -2256,6 +2279,11 @@
                          const std::vector<int>& fds_to_ignore,
                          bool is_priority_fork,
                          bool purge) {
+  ATRACE_CALL();
+  if (is_priority_fork) {
+    setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
+  }
+
   SetSignalHandlers();
 
   // Curry a failure function.
@@ -2341,6 +2369,10 @@
   // We blocked SIGCHLD prior to a fork, we unblock it here.
   UnblockSignal(SIGCHLD, fail_fn);
 
+  if (is_priority_fork && pid != 0) {
+    setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT);
+  }
+
   return pid;
 }
 
@@ -2357,6 +2389,7 @@
         jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list,
         jboolean mount_data_dirs, jboolean mount_storage_dirs) {
     jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
+    jlong bounding_capabilities = CalculateBoundingCapabilities(env, uid, gid, gids);
 
     if (UNLIKELY(managed_fds_to_close == nullptr)) {
       zygote::ZygoteFailure(env, "zygote", nice_name,
@@ -2395,10 +2428,10 @@
 
     if (pid == 0) {
         SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
-                         mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE,
-                         instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list,
-                         allowlisted_data_info_list, mount_data_dirs == JNI_TRUE,
-                         mount_storage_dirs == JNI_TRUE);
+                         bounding_capabilities, mount_external, se_info, nice_name, false,
+                         is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
+                         is_top_app == JNI_TRUE, pkg_data_info_list, allowlisted_data_info_list,
+                         mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE);
     }
     return pid;
 }
@@ -2408,6 +2441,7 @@
         JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
         jlong effective_capabilities) {
+  ATRACE_CALL();
   std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
                    fds_to_ignore(fds_to_close);
 
@@ -2431,7 +2465,7 @@
       // System server prcoess does not need data isolation so no need to
       // know pkg_data_info_list.
       SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
-                       effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
+                       effective_capabilities, 0, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
                        false, nullptr, nullptr, /* is_top_app= */ false,
                        /* pkg_data_info_list */ nullptr,
                        /* allowlisted_data_info_list */ nullptr, false, false);
@@ -2483,6 +2517,7 @@
                                                          jintArray managed_session_socket_fds,
                                                          jboolean args_known,
                                                          jboolean is_priority_fork) {
+  ATRACE_CALL();
   std::vector<int> session_socket_fds =
       ExtractJIntArray(env, "USAP", nullptr, managed_session_socket_fds)
           .value_or(std::vector<int>());
@@ -2498,6 +2533,7 @@
                     bool args_known,
                     bool is_priority_fork,
                     bool purge) {
+  ATRACE_CALL();
 
   std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
                    fds_to_ignore(fds_to_close);
@@ -2588,12 +2624,13 @@
         jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs,
         jboolean mount_storage_dirs) {
     jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
+    jlong bounding_capabilities = CalculateBoundingCapabilities(env, uid, gid, gids);
 
     SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
-                     mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE,
-                     instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list,
-                     allowlisted_data_info_list, mount_data_dirs == JNI_TRUE,
-                     mount_storage_dirs == JNI_TRUE);
+                     bounding_capabilities, mount_external, se_info, nice_name, false,
+                     is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
+                     is_top_app == JNI_TRUE, pkg_data_info_list, allowlisted_data_info_list,
+                     mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE);
 }
 
 /**
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 381580b..00d90cc 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -21,7 +21,6 @@
 per-file android/content/intent.proto = file:/PACKAGE_MANAGER_OWNERS
 
 # Biometrics
-jaggies@google.com
 jbolinger@google.com
 
 # Launcher
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f5635f4..720324c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5758,7 +5758,7 @@
     <permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to collect usage infomation about brightness slider changes.
+    <!-- Allows an application to collect usage information about brightness slider changes.
          <p>Not for use by third-party applications.</p>
          @hide
          @SystemApi
diff --git a/core/res/OWNERS b/core/res/OWNERS
index f24c3f5..36daa7d 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -8,7 +8,6 @@
 hackbod@android.com
 hackbod@google.com
 ilyamaty@google.com
-jaggies@google.com
 jbolinger@google.com
 jsharkey@android.com
 jsharkey@google.com
diff --git a/core/res/res/layout/app_perms_summary.xml b/core/res/res/layout/app_perms_summary.xml
index b8d93ac..509b988 100644
--- a/core/res/res/layout/app_perms_summary.xml
+++ b/core/res/res/layout/app_perms_summary.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<!-- Describes permission item consisting of a group name and the list of permisisons under the group -->
+<!-- Describes permission item consisting of a group name and the list of permissions under the group -->
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 9bb2499..61e6a36 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -127,7 +127,7 @@
     <!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
          http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
          visual voicemail code for Orange: 21101 -->
-    <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366|555|2051" />
+    <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366|555|2051|33033" />
 
     <!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
          http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf,
@@ -150,6 +150,9 @@
          http://clients.txtnation.com/entries/209633-hungary-premium-sms-short-code-regulations -->
     <shortcode country="hu" pattern="[01](?:\\d{3}|\\d{9})" premium="0691227910|1784" free="116\\d{3}" />
 
+    <!-- Honduras -->
+    <shortcode country="hn" pattern="\\d{4,6}" free="466453" />
+
     <!-- India: 1-5 digits (standard system default, not country specific) -->
     <shortcode country="in" pattern="\\d{1,5}" free="59336|53969" />
 
@@ -171,7 +174,7 @@
     <shortcode country="jp" pattern="\\d{1,5}" free="8083" />
 
     <!-- Kenya: 5 digits, known premium codes listed -->
-    <shortcode country="ke" pattern="\\d{5}" free="21725|21562|40520|23342|40023" />
+    <shortcode country="ke" pattern="\\d{5}" free="21725|21562|40520|23342|40023|24088|23054" />
 
     <!-- Kyrgyzstan: 4 digits, known premium codes listed -->
     <shortcode country="kg" pattern="\\d{4}" premium="415[2367]|444[69]" />
@@ -183,7 +186,7 @@
     <shortcode country="kz" pattern="\\d{4}" premium="335[02]|4161|444[469]|77[2359]0|8444|919[3-5]|968[2-5]" />
 
     <!-- Kuwait: 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="kw" pattern="\\d{1,5}" free="1378|50420|94006|55991" />
+    <shortcode country="kw" pattern="\\d{1,5}" free="1378|50420|94006|55991|50976" />
 
     <!-- Lithuania: 3-5 digits, known premium codes listed, plus EU -->
     <shortcode country="lt" pattern="\\d{3,5}" premium="13[89]1|1394|16[34]5" free="116\\d{3}|1399|1324" />
@@ -195,9 +198,18 @@
     <!-- Latvia: 4 digits, known premium codes listed, plus EU -->
     <shortcode country="lv" pattern="\\d{4}" premium="18(?:19|63|7[1-4])" free="116\\d{3}|1399" />
 
+    <!-- Morocco: 1-5 digits (standard system default, not country specific) -->
+    <shortcode country="ma" pattern="\\d{1,5}" free="53819" />
+
     <!-- Macedonia: 1-6 digits (not confirmed), known premium codes listed -->
     <shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
 
+    <!-- Malawi: 1-5 digits (standard system default, not country specific) -->
+    <shortcode country="mw" pattern="\\d{1,5}" free="4276" />
+
+    <!-- Mozambique: 1-5 digits (standard system default, not country specific) -->
+    <shortcode country="mz" pattern="\\d{1,5}" free="1714" />
+
     <!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
     <shortcode country="mx" pattern="\\d{4,6}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346" />
 
@@ -207,6 +219,9 @@
     <!-- Namibia: 1-5 digits (standard system default, not country specific) -->
     <shortcode country="na" pattern="\\d{1,5}" free="40005" />
 
+    <!-- Nicaragua -->
+    <shortcode country="ni" pattern="\\d{4,6}" free="466453" />
+
     <!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
     <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" />
 
@@ -219,8 +234,8 @@
     <!-- New Zealand: 3-4 digits, known premium codes listed -->
     <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|176|2141|3067|3068|3110|3876|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" />
 
-    <!-- Peru: 4-5 digits (not confirmed), known premium codes listed -->
-    <shortcode country="pe" pattern="\\d{4,5}" free="9963|40778" />
+    <!-- Peru: 4-6 digits (not confirmed), known premium codes listed -->
+    <shortcode country="pe" pattern="\\d{4,6}" free="9963|40778|301303" />
 
     <!-- Philippines -->
     <shortcode country="ph" pattern="\\d{1,5}" free="2147|5495|5496" />
@@ -269,6 +284,12 @@
     <!-- Slovakia: 4 digits (premium), plus EU: http://www.cmtelecom.com/premium-sms/slovakia -->
     <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" />
+
+    <!-- El Salvador(SV): 1-5 digits (standard system default, not country specific) -->
+    <shortcode country="sv" pattern="\\d{4,6}" free="466453" />
+
     <!-- Taiwan -->
     <shortcode country="tw" pattern="\\d{4}" free="1922" />
 
@@ -278,15 +299,21 @@
     <!-- Tajikistan: 4 digits, known premium codes listed -->
     <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
 
+    <!-- Tanzania: 1-5 digits (standard system default, not country specific) -->
+    <shortcode country="tz" pattern="\\d{1,5}" free="15046|15234" />
+
     <!-- Turkey -->
     <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493|3193" />
 
     <!-- Ukraine: 4 digits, known premium codes listed -->
     <shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" />
 
+    <!-- Uganda(UG): 4 digits (standard system default, not country specific) -->
+    <shortcode country="ug" pattern="\\d{4}" free="8000" />
+
     <!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm),
          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" />
+    <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" />
 
     <!-- Vietnam: 1-5 digits (standard system default, not country specific) -->
     <shortcode country="vn" pattern="\\d{1,5}" free="5001|9055" />
diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp
index 054d10c..39ea6e6 100644
--- a/core/tests/BroadcastRadioTests/Android.bp
+++ b/core/tests/BroadcastRadioTests/Android.bp
@@ -18,6 +18,7 @@
     // all of the 'license_kinds' from "frameworks_base_license"
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
+    default_team: "trendy_team_aaos_framework",
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
index 6a6a951..00afba8d 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
@@ -264,7 +264,7 @@
         int scanStatus = mRadioTuner.scan(RadioTuner.DIRECTION_DOWN, /* skipSubChannel= */ false);
 
         verify(mTunerMock).seek(/* directionDown= */ true, /* skipSubChannel= */ false);
-        assertWithMessage("Status for scaning")
+        assertWithMessage("Status for scanning")
                 .that(scanStatus).isEqualTo(RadioManager.STATUS_OK);
         verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onProgramInfoChanged(FM_PROGRAM_INFO);
     }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index 0806fa0..db95d7a 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -99,7 +99,7 @@
         }
     }
 
-    public int getSoftApInterations() {
+    public int getSoftApIterations() {
         return mSoftApIterations;
     }
 
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index c4530f6..cb803f7 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -124,6 +124,10 @@
         <group gid="security_log_writer" />
     </permission>
 
+    <permission name="android.permission.MANAGE_VIRTUAL_MACHINE">
+        <group gid="virtualmachine" />
+    </permission>
+
     <!-- These are permissions that were mapped to gids but we need
          to keep them here until an upgrade from L to the current
          version is to be supported. These permissions are built-in
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 1da8e18..d915b74 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -25,10 +25,13 @@
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.Trace;
+import android.system.OsConstants;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
 
+import libcore.io.IoBridge;
+
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -523,19 +526,19 @@
     public static Bitmap decodeFile(String pathName, Options opts) {
         validate(opts);
         Bitmap bm = null;
-        InputStream stream = null;
+        FileDescriptor fd = null;
         try {
-            stream = new FileInputStream(pathName);
-            bm = decodeStream(stream, null, opts);
+            fd = IoBridge.open(pathName, OsConstants.O_RDONLY);
+            bm = decodeFileDescriptor(fd, null, opts);
         } catch (Exception e) {
             /*  do nothing.
                 If the exception happened on open, bm will be null.
             */
-            Log.e("BitmapFactory", "Unable to decode stream: " + e);
+            Log.e("BitmapFactory", "Unable to decode file: " + e);
         } finally {
-            if (stream != null) {
+            if (fd != null) {
                 try {
-                    stream.close();
+                    IoBridge.closeAndSignalBlockedThreads(fd);
                 } catch (IOException e) {
                     // do nothing here
                 }
diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java
index 0e198d5..1200ff9 100644
--- a/graphics/java/android/view/PixelCopy.java
+++ b/graphics/java/android/view/PixelCopy.java
@@ -96,7 +96,7 @@
      *
      * The contents of the source will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the SurfaceView's Surface will be used as the source of the copy.
      *
      * @param source The source from which to copy
@@ -117,7 +117,7 @@
      *
      * The contents of the source will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the SurfaceView's Surface will be used as the source of the copy.
      *
      * @param source The source from which to copy
@@ -143,7 +143,7 @@
      *
      * The contents of the source will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the Surface will be used as the source of the copy.
      *
      * @param source The source from which to copy
@@ -164,7 +164,7 @@
      *
      * The contents of the source rect will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the Surface will be used as the source of the copy.
      *
      * @param source The source from which to copy
@@ -201,7 +201,7 @@
      *
      * The contents of the source will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the Window's Surface will be used as the source of the copy.
      *
      * Note: This is limited to being able to copy from Window's with a non-null
@@ -231,7 +231,7 @@
      *
      * The contents of the source rect will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the Window's Surface will be used as the source of the copy.
      *
      * Note: This is limited to being able to copy from Window's with a non-null
diff --git a/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl b/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
index c360cb8..cfc5980 100644
--- a/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
+++ b/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
@@ -20,8 +20,14 @@
 
 /** @hide */
 interface IKeyAttestationApplicationIdProvider {
+    const int ERROR_GET_ATTESTATION_APPLICATION_ID_FAILED = 1;
+
     /**
      * Provides information describing the possible applications identified by a UID.
+     *
+     * In case of not getting package ids from uid return
+     * {@link #ERROR_GET_ATTESTATION_APPLICATION_ID_FAILED} to the caller.
+     *
      * @hide
      */
     KeyAttestationApplicationId getKeyAttestationApplicationId(int uid);
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 2beb434..2430e8d 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.os.StrictMode;
@@ -218,4 +219,28 @@
             return SYSTEM_ERROR;
         }
     }
+
+    /**
+     * Returns the list of Application UIDs that have auth-bound keys that are bound to
+     * the given SID. This enables warning the user when they are about to invalidate
+     * a SID (for example, removing the LSKF).
+     *
+     * @param userId - The ID of the user the SID is associated with.
+     * @param userSecureId - The SID in question.
+     *
+     * @return A list of app UIDs.
+     */
+    public static long[] getAllAppUidsAffectedBySid(int userId, long userSecureId)
+            throws KeyStoreException {
+        StrictMode.noteDiskWrite();
+        try {
+            return getService().getAppUidsAffectedBySid(userId, userSecureId);
+        } catch (RemoteException | NullPointerException e) {
+            throw new KeyStoreException(SYSTEM_ERROR,
+                    "Failure to connect to Keystore while trying to get apps affected by SID.");
+        } catch (ServiceSpecificException e) {
+            throw new KeyStoreException(e.errorCode,
+                    "Keystore error while trying to get apps affected by SID.");
+        }
+    }
 }
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 4982f37..244fe30 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -618,7 +618,7 @@
      * @see #isMgf1DigestsSpecified()
      */
     @NonNull
-    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
     public @KeyProperties.DigestEnum Set<String> getMgf1Digests() {
         if (mMgf1Digests.isEmpty()) {
             throw new IllegalStateException("Mask generation function (MGF) not specified");
@@ -633,7 +633,7 @@
      * @see #getMgf1Digests()
      */
     @NonNull
-    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
     public boolean isMgf1DigestsSpecified() {
         return !mMgf1Digests.isEmpty();
     }
@@ -1292,7 +1292,7 @@
          * <p>See {@link KeyProperties}.{@code DIGEST} constants.
          */
         @NonNull
-        @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+        @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
         public Builder setMgf1Digests(@NonNull @KeyProperties.DigestEnum String... mgf1Digests) {
             mMgf1Digests = Set.of(mgf1Digests);
             return this;
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 7b6b2d1..2495d1a 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -401,7 +401,7 @@
      * @see #isMgf1DigestsSpecified()
      */
     @NonNull
-    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
     public @KeyProperties.DigestEnum Set<String> getMgf1Digests() {
         if (mMgf1Digests.isEmpty()) {
             throw new IllegalStateException("Mask generation function (MGF) not specified");
@@ -416,7 +416,7 @@
      * @see #getMgf1Digests()
      */
     @NonNull
-    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+    @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
     public boolean isMgf1DigestsSpecified() {
         return !mMgf1Digests.isEmpty();
     }
@@ -799,7 +799,7 @@
          * <p>See {@link KeyProperties}.{@code DIGEST} constants.
          */
         @NonNull
-        @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER)
+        @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER_V2)
         public Builder setMgf1Digests(@Nullable @KeyProperties.DigestEnum String... mgf1Digests) {
             mMgf1Digests = Set.of(mgf1Digests);
             return this;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 83ddfc5..e6c652c 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -974,7 +974,7 @@
 
     private static boolean getMgf1DigestSetterFlag() {
         try {
-            return Flags.mgf1DigestSetter();
+            return Flags.mgf1DigestSetterV2();
         } catch (SecurityException e) {
             Log.w(TAG, "Cannot read MGF1 Digest setter flag value", e);
             return false;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 2d8c5a3..e6a63b9 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -259,7 +259,7 @@
 
     private static boolean getMgf1DigestSetterFlag() {
         try {
-            return Flags.mgf1DigestSetter();
+            return Flags.mgf1DigestSetterV2();
         } catch (SecurityException e) {
             Log.w(NAME, "Cannot read MGF1 Digest setter flag value", e);
             return false;
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index 9211c53..65cc1c4 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -31,7 +31,7 @@
  * device at the boundary of the audio system.
  * In addition to base audio port attributes, the device descriptor contains:
  * - the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
- * - the device address (e.g MAC adddress for AD2P sink).
+ * - the device address (e.g MAC address for AD2P sink).
  * @see AudioPort
  * @hide
  */
diff --git a/media/java/android/media/AudioHalVersionInfo.java b/media/java/android/media/AudioHalVersionInfo.java
index efb3395..472cb3f 100644
--- a/media/java/android/media/AudioHalVersionInfo.java
+++ b/media/java/android/media/AudioHalVersionInfo.java
@@ -76,9 +76,12 @@
     /**
      * List of all valid Audio HAL versions. This list need to be in sync with sAudioHALVersions
      * defined in frameworks/av/media/libaudiohal/FactoryHal.cpp.
+     *
+     * Note: update {@link android.media.audio.cts.AudioHalVersionInfoTest} CTS accordingly if
+     * there is a change to supported versions.
      */
     public static final @NonNull List<AudioHalVersionInfo> VERSIONS =
-            List.of(AIDL_1_0, HIDL_7_1, HIDL_7_0, HIDL_6_0, HIDL_5_0, HIDL_4_0);
+            List.of(AIDL_1_0, HIDL_7_1, HIDL_7_0, HIDL_6_0, HIDL_5_0);
 
     private static final String TAG = "AudioHalVersionInfo";
     private AudioHalVersion mHalVersion = new AudioHalVersion();
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 862ae8d..b9aee28 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,6 +16,11 @@
 
 package android.media;
 
+import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
+import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
+
+import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
+
 import android.Manifest;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
@@ -51,7 +56,6 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -62,7 +66,6 @@
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
 /**
  MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components.
  It is part of the Android low-level multimedia support infrastructure (normally used together
@@ -2211,6 +2214,18 @@
      */
     public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4;
 
+    /**
+     * Configure the codec with a detached output surface.
+     * <p>
+     * This flag is only defined for a video decoder. MediaCodec
+     * configured with this flag will be in Surface mode even though
+     * the surface parameter is null.
+     *
+     * @see detachOutputSurface
+     */
+    @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+    public static final int CONFIGURE_FLAG_DETACHED_SURFACE = 8;
+
     /** @hide */
     @IntDef(
         flag = true,
@@ -2393,6 +2408,31 @@
     private native void native_setSurface(@NonNull Surface surface);
 
     /**
+     *  Detach the current output surface of a codec.
+     *  <p>
+     *  Detaches the currently associated output Surface from the
+     *  MediaCodec decoder. This allows the SurfaceView or other
+     *  component holding the Surface to be safely destroyed or
+     *  modified without affecting the decoder's operation. After
+     *  calling this method (and after it returns), the decoder will
+     *  enter detached-Surface mode and will no longer render
+     *  output.
+     *
+     *  @throws IllegalStateException if the codec was not
+     *                                configured in surface mode.
+     *  @see CONFIGURE_FLAG_DETACHED_SURFACE
+     */
+    @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+    public void detachOutputSurface() {
+        if (!mHasSurface) {
+            throw new IllegalStateException("codec was not configured for an output surface");
+        }
+        // note: we still have a surface in detached mode, so keep mHasSurface
+        // we also technically allow calling detachOutputSurface multiple times in a row
+        // native_detachSurface();
+    }
+
+    /**
      * Create a persistent input surface that can be used with codecs that normally have an input
      * surface, such as video encoders. A persistent input can be reused by subsequent
      * {@link MediaCodec} or {@link MediaRecorder} instances, but can only be used by at
@@ -3210,6 +3250,51 @@
         }
     }
 
+    /**
+     * Similar to {@link #queueInputBuffers queueInputBuffers} but submits multiple access units
+     * in a buffer that is potentially encrypted.
+     * <strong>Check out further notes at {@link #queueInputBuffers queueInputBuffers}.</strong>
+     *
+     * @param index The index of a client-owned input buffer previously returned
+     *              in a call to {@link #dequeueInputBuffer}.
+     * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
+     *                    contents in the buffer. The ArrayDeque and the BufferInfo objects provided
+     *                    can be recycled by the caller for re-use.
+     * @param cryptoInfos ArrayDeque of {@link MediaCodec.CryptoInfo} objects to facilitate the
+     *                    decryption of the contents. The ArrayDeque and the CryptoInfo objects
+     *                    provided can be reused immediately after the call returns. These objects
+     *                    should correspond to bufferInfo objects to ensure correct decryption.
+     * @throws IllegalStateException if not in the Executing state or not in asynchronous mode.
+     * @throws MediaCodec.CodecException upon codec error.
+     * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
+     *                    access units are not contiguous.
+     * @throws CryptoException if an error occurs while attempting to decrypt the buffer.
+     *              An error code associated with the exception helps identify the
+     *              reason for the failure.
+     */
+    @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+    public final void queueSecureInputBuffers(
+            int index,
+            @NonNull ArrayDeque<BufferInfo> bufferInfos,
+            @NonNull ArrayDeque<CryptoInfo> cryptoInfos) {
+        synchronized(mBufferLock) {
+            if (mBufferMode == BUFFER_MODE_BLOCK) {
+                throw new IncompatibleWithBlockModelException("queueSecureInputBuffers() "
+                        + "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+                        + "Please use getQueueRequest() to queue buffers");
+            }
+            invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
+            mDequeuedInputBuffers.remove(index);
+        }
+        try {
+            native_queueSecureInputBuffers(
+                    index, bufferInfos.toArray(), cryptoInfos.toArray());
+        } catch (CryptoException | IllegalStateException | IllegalArgumentException e) {
+            revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
+            throw e;
+        }
+    }
+
     private native final void native_queueSecureInputBuffer(
             int index,
             int offset,
@@ -3217,6 +3302,11 @@
             long presentationTimeUs,
             int flags) throws CryptoException;
 
+    private native final void native_queueSecureInputBuffers(
+            int index,
+            @NonNull Object[] bufferInfos,
+            @NonNull Object[] cryptoInfos) throws CryptoException, CodecException;
+
     /**
      * Returns the index of an input buffer to be filled with valid data
      * or -1 if no such buffer is currently available.
@@ -3462,7 +3552,7 @@
             mLinearBlock = block;
             mOffset = offset;
             mSize = size;
-            mCryptoInfo = null;
+            mCryptoInfos.clear();
             return this;
         }
 
@@ -3496,7 +3586,44 @@
             mLinearBlock = block;
             mOffset = offset;
             mSize = size;
-            mCryptoInfo = cryptoInfo;
+            mCryptoInfos.clear();
+            mCryptoInfos.add(cryptoInfo);
+            return this;
+        }
+
+        /**
+         * Set an encrypted linear block to this queue request. Exactly one buffer must be
+         * set for a queue request before calling {@link #queue}. The block can contain multiple
+         * access units and if present should be laid out contiguously and without gaps.
+         *
+         * @param block The linear block object
+         * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
+         *                    contents in the buffer. The ArrayDeque and the BufferInfo objects
+         *                    provided can be recycled by the caller for re-use.
+         * @param cryptoInfos ArrayDeque of {@link MediaCodec.CryptoInfo} that describes the
+         *                    structure of the encrypted input samples. The ArrayDeque and the
+         *                    BufferInfo objects provided can be recycled by the caller for re-use.
+         * @return this object
+         * @throws IllegalStateException if a buffer is already set
+         * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
+         *                     access units are not contiguous.
+         */
+        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+        public @NonNull QueueRequest setMultiFrameEncryptedLinearBlock(
+                @NonNull LinearBlock block,
+                @NonNull ArrayDeque<MediaCodec.BufferInfo> bufferInfos,
+                @NonNull ArrayDeque<MediaCodec.CryptoInfo> cryptoInfos) {
+            if (!isAccessible()) {
+                throw new IllegalStateException("The request is stale");
+            }
+            if (mLinearBlock != null || mHardwareBuffer != null) {
+                throw new IllegalStateException("Cannot set block twice");
+            }
+            mLinearBlock = block;
+            mBufferInfos.clear();
+            mBufferInfos.addAll(bufferInfos);
+            mCryptoInfos.clear();
+            mCryptoInfos.addAll(cryptoInfos);
             return this;
         }
 
@@ -3706,8 +3833,10 @@
                 mBufferInfos.add(info);
             }
             if (mLinearBlock != null) {
+
                 mCodec.native_queueLinearBlock(
-                        mIndex, mLinearBlock, mCryptoInfo,
+                        mIndex, mLinearBlock,
+                        mCryptoInfos.isEmpty() ? null : mCryptoInfos.toArray(),
                         mBufferInfos.toArray(),
                         mTuningKeys, mTuningValues);
             } else if (mHardwareBuffer != null) {
@@ -3722,11 +3851,11 @@
             mLinearBlock = null;
             mOffset = 0;
             mSize = 0;
-            mCryptoInfo = null;
             mHardwareBuffer = null;
             mPresentationTimeUs = 0;
             mFlags = 0;
             mBufferInfos.clear();
+            mCryptoInfos.clear();
             mTuningKeys.clear();
             mTuningValues.clear();
             return this;
@@ -3746,11 +3875,11 @@
         private LinearBlock mLinearBlock = null;
         private int mOffset = 0;
         private int mSize = 0;
-        private MediaCodec.CryptoInfo mCryptoInfo = null;
         private HardwareBuffer mHardwareBuffer = null;
         private long mPresentationTimeUs = 0;
         private @BufferFlag int mFlags = 0;
         private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
+        private final ArrayDeque<CryptoInfo> mCryptoInfos = new ArrayDeque<>();
         private final ArrayList<String> mTuningKeys = new ArrayList<>();
         private final ArrayList<Object> mTuningValues = new ArrayList<>();
 
@@ -3760,7 +3889,7 @@
     private native void native_queueLinearBlock(
             int index,
             @NonNull LinearBlock block,
-            @Nullable CryptoInfo cryptoInfo,
+            @Nullable Object[] cryptoInfos,
             @NonNull Object[] bufferInfos,
             @NonNull ArrayList<String> keys,
             @NonNull ArrayList<Object> values);
@@ -4936,6 +5065,68 @@
     public static final String PARAMETER_KEY_TUNNEL_PEEK = "tunnel-peek";
 
     /**
+     * Set the region of interest as QpOffset-Map on the next queued input frame.
+     * <p>
+     * The associated value is a byte array containing quantization parameter (QP) offsets in
+     * raster scan order for the entire frame at 16x16 granularity. The size of the byte array
+     * shall be ((frame_width + 15) / 16) * ((frame_height + 15) / 16), where frame_width and
+     * frame_height correspond to width and height configured using {@link MediaFormat#KEY_WIDTH}
+     * and {@link MediaFormat#KEY_HEIGHT} keys respectively. During encoding, if the coding unit
+     * 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
+     * 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.
+     * <p>
+     * If byte array size is too small than the expected size, components may ignore the
+     * configuration silently. If the byte array exceeds the expected size, components shall use
+     * the initial portion and ignore the rest.
+     * <p>
+     * The scope of this key is throughout the encoding session until it is reconfigured during
+     * running state.
+     * <p>
+     * @see #setParameters(Bundle)
+     */
+    @FlaggedApi(FLAG_REGION_OF_INTEREST)
+    public static final String PARAMETER_KEY_QP_OFFSET_MAP = "qp-offset-map";
+
+    /**
+     * Set the region of interest as QpOffset-Rects on the next queued input frame.
+     * <p>
+     * The associated value is a String in the format "Top1,Left1-Bottom1,Right1=Offset1;Top2,
+     * Left2-Bottom2,Right2=Offset2;...". Co-ordinates (Top, Left), (Top, Right), (Bottom, Left)
+     * and (Bottom, Right) form the vertices of bounding box of region of interest in pixels.
+     * Pixel (0, 0) points to the top-left corner of the frame. Offset is the suggested
+     * quantization parameter (QP) offset of the blocks in the bounding box. The bounding box
+     * 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
+     * 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
+     * improved.
+     * <p>
+     * If Roi rect is not valid that is bounding box width is < 0 or bounding box height is < 0,
+     * components may ignore the configuration silently. If Roi rect extends outside frame
+     * boundaries, then rect shall be clamped to the frame boundaries.
+     * <p>
+     * The scope of this key is throughout the encoding session until it is reconfigured during
+     * running state.
+     * <p>
+     * The maximum number of contours (rectangles) that can be specified for a given input frame
+     * is device specific. Implementations will drop/ignore the rectangles that are beyond their
+     * supported limit. Hence it is preferable to place the rects in descending order of
+     * importance. Transitively, if the bounding boxes overlap, then the most preferred
+     * rectangle's qp offset (earlier rectangle qp offset) will be used to quantize the block.
+     * <p>
+     * @see #setParameters(Bundle)
+     */
+    @FlaggedApi(FLAG_REGION_OF_INTEREST)
+    public static final String PARAMETER_KEY_QP_OFFSET_RECTS = "qp-offset-rects";
+
+    /**
      * Communicate additional parameter changes to the component instance.
      * <b>Note:</b> Some of these parameter changes may silently fail to apply.
      *
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 88b9643..3174c37 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -18,7 +18,12 @@
 
 import static android.media.Utils.intersectSortedDistinctRanges;
 import static android.media.Utils.sortDistinctRanges;
+import static android.media.codec.Flags.FLAG_DYNAMIC_COLOR_ASPECTS;
+import static android.media.codec.Flags.FLAG_HLG_EDITING;
+import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
+import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -692,6 +697,99 @@
         public static final String FEATURE_HdrEditing = "hdr-editing";
 
         /**
+         * <b>video encoder only</b>: codec supports HLG editing.
+         * <p>
+         * HLG editing support means that the codec accepts 10-bit HDR
+         * input surface in both YUV and RGB pixel format. This feature
+         * is only meaningful when using a 10-bit (HLG) profile and
+         * 10-bit input.
+         * <p>
+         * This feature implies that the codec is capable of encoding
+         * 10-bit format, and that it supports RGBA_1010102 as
+         * well as P010, and optionally RGBA_FP16 input formats.
+         * <p>
+         * The difference between this feature and {@link
+         * FEATURE_HdrEditing} is that HLG does not require the
+         * generation of HDR metadata and does not use an explicit HDR
+         * profile.
+         */
+        @SuppressLint("AllUpper")
+        @FlaggedApi(FLAG_HLG_EDITING)
+        public static final String FEATURE_HlgEditing = "hlg-editing";
+
+        /**
+         * <b>video decoder only</b>: codec supports dynamically
+         * changing color aspects.
+         * <p>
+         * If true, the codec can propagate color aspect changes during
+         * decoding. This is only meaningful at session boundaries, e.g.
+         * upon processing Picture Parameter Sets prior to a new IDR.
+         * The color aspects may come from the bitstream, or may be
+         * provided using {@link MediaCodec#setParameters} calls.
+         * <p>
+         * If the codec supports both 8-bit and 10-bit profiles, this
+         * feature means that the codec can dynamically switch between 8
+         * and 10-bit profiles, but this is restricted to Surface mode
+         * only.
+         * <p>
+         * If the device supports HDR transfer functions, switching
+         * between SDR and HDR transfer is also supported. Together with
+         * the previous clause this means that switching between SDR and
+         * HDR sessions are supported in Surface mode, as SDR is
+         * typically encoded at 8-bit and HDR at 10-bit.
+         */
+        @SuppressLint("AllUpper")
+        @FlaggedApi(FLAG_DYNAMIC_COLOR_ASPECTS)
+        public static final String FEATURE_DynamicColorAspects = "dynamic-color-aspects";
+
+        /**
+         * <b>video encoder only</b>: codec supports region of interest encoding.
+         * <p>
+         * RoI encoding support means the codec accepts information that specifies the relative
+         * importance of different portions of each video frame. This allows the encoder to
+         * separate a video frame into critical and non-critical regions, and use more bits
+         * (better quality) to represent the critical regions and de-prioritize non-critical
+         * regions. In other words, the encoder chooses a negative qp bias for the critical
+         * portions and a zero or positive qp bias for the non-critical portions.
+         * <p>
+         * At a basic level, if the encoder decides to encode each frame with a uniform
+         * quantization value 'qpFrame' and a 'qpBias' is chosen/suggested for an LCU of the
+         * frame, then the actual qp of the LCU will be 'qpFrame + qpBias', although this value
+         * can be clamped basing on the min-max configured qp bounds for the current encoding
+         * session.
+         * <p>
+         * In a shot, if a group of LCUs pan out quickly they can be marked as non-critical
+         * thereby enabling the encoder to reserve fewer bits during their encoding. Contrarily,
+         * LCUs that remain in shot for a prolonged duration can be encoded at better quality in
+         * one frame thereby setting-up an excellent long-term reference for all future frames.
+         * <p>
+         * Note that by offsetting the quantization of each LCU, the overall bit allocation will
+         * differ from the originally estimated bit allocation, and the encoder will adjust the
+         * frame quantization for subsequent frames to meet the bitrate target. An effective
+         * selection of critical regions can set-up a golden reference and this can compensate
+         * for the bit burden that was introduced due to encoding RoI's at better quality.
+         * On the other hand, an ineffective choice of critical regions might increase the
+         * quality of certain parts of the image but this can hamper quality in subsequent frames.
+         * <p>
+         * @see MediaCodec#PARAMETER_KEY_QP_OFFSET_MAP
+         * @see MediaCodec#PARAMETER_KEY_QP_OFFSET_RECTS
+         */
+        @SuppressLint("AllUpper")
+        @FlaggedApi(FLAG_REGION_OF_INTEREST)
+        public static final String FEATURE_Roi = "region-of-interest";
+
+        /**
+         * <b>video decoder only</b>: codec supports detaching the
+         * output surface when in Surface mode.
+         * <p> If true, the codec can be configured in Surface mode
+         * without an actual surface (in detached surface mode).
+         * @see MediaCodec#CONFIGURE_FLAG_DETACHED_SURFACE
+         */
+        @SuppressLint("AllUpper")
+        @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+        public static final String FEATURE_DetachedSurface = "detached-surface";
+
+        /**
          * Query codec feature capabilities.
          * <p>
          * These features are supported to be used by the codec.  These
@@ -712,29 +810,66 @@
             return checkFeature(name, mFlagsRequired);
         }
 
-        private static final Feature[] decoderFeatures = {
-            new Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
-            new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
-            new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
-            new Feature(FEATURE_PartialFrame,     (1 << 3), false),
-            new Feature(FEATURE_FrameParsing,     (1 << 4), false),
-            new Feature(FEATURE_MultipleFrames,   (1 << 5), false),
-            new Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
-            new Feature(FEATURE_LowLatency,       (1 << 7), true),
-            // feature to exclude codec from REGULAR codec list
-            new Feature(FEATURE_SpecialCodec,     (1 << 30), false, true),
-        };
+        // Flags are used for feature list creation so separate this into a private
+        // static class to delay reading the flags only when constructing the list.
+        private static class FeatureList {
+            private static Feature[] getDecoderFeatures() {
+                ArrayList<Feature> features = new ArrayList();
+                features.add(new Feature(FEATURE_AdaptivePlayback, (1 << 0), true));
+                features.add(new Feature(FEATURE_SecurePlayback,   (1 << 1), false));
+                features.add(new Feature(FEATURE_TunneledPlayback, (1 << 2), false));
+                features.add(new Feature(FEATURE_PartialFrame,     (1 << 3), false));
+                features.add(new Feature(FEATURE_FrameParsing,     (1 << 4), false));
+                features.add(new Feature(FEATURE_MultipleFrames,   (1 << 5), false));
+                features.add(new Feature(FEATURE_DynamicTimestamp, (1 << 6), false));
+                features.add(new Feature(FEATURE_LowLatency,       (1 << 7), true));
+                if (android.media.codec.Flags.dynamicColorAspects()) {
+                    features.add(new Feature(FEATURE_DynamicColorAspects, (1 << 8), true));
+                }
+                if (android.media.codec.Flags.nullOutputSurface()) {
+                    features.add(new Feature(FEATURE_DetachedSurface,     (1 << 9), true));
+                }
 
-        private static final Feature[] encoderFeatures = {
-            new Feature(FEATURE_IntraRefresh, (1 << 0), false),
-            new Feature(FEATURE_MultipleFrames, (1 << 1), false),
-            new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
-            new Feature(FEATURE_QpBounds, (1 << 3), false),
-            new Feature(FEATURE_EncodingStatistics, (1 << 4), false),
-            new Feature(FEATURE_HdrEditing, (1 << 5), false),
-            // feature to exclude codec from REGULAR codec list
-            new Feature(FEATURE_SpecialCodec,     (1 << 30), false, true),
-        };
+                // feature to exclude codec from REGULAR codec list
+                features.add(new Feature(FEATURE_SpecialCodec,     (1 << 30), false, true));
+
+                return features.toArray(new Feature[0]);
+            };
+
+            private static Feature[] decoderFeatures = getDecoderFeatures();
+
+            private static Feature[] getEncoderFeatures() {
+                ArrayList<Feature> features = new ArrayList();
+
+                features.add(new Feature(FEATURE_IntraRefresh, (1 << 0), false));
+                features.add(new Feature(FEATURE_MultipleFrames, (1 << 1), false));
+                features.add(new Feature(FEATURE_DynamicTimestamp, (1 << 2), false));
+                features.add(new Feature(FEATURE_QpBounds, (1 << 3), false));
+                features.add(new Feature(FEATURE_EncodingStatistics, (1 << 4), false));
+                features.add(new Feature(FEATURE_HdrEditing, (1 << 5), false));
+                if (android.media.codec.Flags.hlgEditing()) {
+                    features.add(new Feature(FEATURE_HlgEditing, (1 << 6), true));
+                }
+                if (android.media.codec.Flags.regionOfInterest()) {
+                    features.add(new Feature(FEATURE_Roi, (1 << 7), true));
+                }
+
+                // feature to exclude codec from REGULAR codec list
+                features.add(new Feature(FEATURE_SpecialCodec,     (1 << 30), false, true));
+
+                return features.toArray(new Feature[0]);
+            };
+
+            private static Feature[] encoderFeatures = getEncoderFeatures();
+
+            public static Feature[] getFeatures(boolean isEncoder) {
+                if (isEncoder) {
+                    return encoderFeatures;
+                } else {
+                    return decoderFeatures;
+                }
+            }
+        }
 
         /** @hide */
         public String[] validFeatures() {
@@ -749,10 +884,7 @@
         }
 
         private Feature[] getValidFeatures() {
-            if (!isEncoder()) {
-                return decoderFeatures;
-            }
-            return encoderFeatures;
+            return FeatureList.getFeatures(isEncoder());
         }
 
         private boolean checkFeature(String name, int flags) {
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index 058c5be..5d470ae 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -14,3 +14,5 @@
 
 # Haptics team also works on Ringtone
 per-file *Ringtone* = file:/services/core/java/com/android/server/vibrator/OWNERS
+
+per-file flags/projection.aconfig = file:projection/OWNERS
\ No newline at end of file
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 8cdd59e..8396005 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -458,6 +458,24 @@
             presentationTimeUs, flags, errorDetailMsg);
 }
 
+status_t JMediaCodec::queueSecureInputBuffers(
+        size_t index,
+        size_t offset,
+        size_t size,
+        const sp<RefBase> &auInfos_,
+        const sp<RefBase> &cryptoInfos_,
+        AString *errorDetailMsg) {
+    sp<BufferInfosWrapper> auInfos((BufferInfosWrapper *)auInfos_.get());
+    sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
+    return mCodec->queueSecureInputBuffers(
+            index,
+            offset,
+            size,
+            auInfos,
+            cryptoInfos,
+            errorDetailMsg);
+}
+
 status_t JMediaCodec::queueBuffer(
         size_t index, const std::shared_ptr<C2Buffer> &buffer,
         const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
@@ -470,19 +488,16 @@
         size_t index,
         const sp<hardware::HidlMemory> &buffer,
         size_t offset,
-        const CryptoPlugin::SubSample *subSamples,
-        size_t numSubSamples,
-        const uint8_t key[16],
-        const uint8_t iv[16],
-        CryptoPlugin::Mode mode,
-        const CryptoPlugin::Pattern &pattern,
+        size_t size,
         const sp<RefBase> &infos,
+        const sp<RefBase> &cryptoInfos_,
         const sp<AMessage> &tunings,
         AString *errorDetailMsg) {
     sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
+    sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
     return mCodec->queueEncryptedBuffer(
-            index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
-            auInfo, tunings, errorDetailMsg);
+            index, buffer, offset, size, auInfo, cryptoInfos,
+            tunings, errorDetailMsg);
 }
 
 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
@@ -2262,6 +2277,61 @@
     CryptoPlugin::Pattern mPattern;
 };
 
+// This class takes away all dependencies on java(env and jni) and
+// could be used for taking cryptoInfo objects to MediaCodec.
+struct MediaCodecCryptoInfo: public CodecCryptoInfo {
+    explicit MediaCodecCryptoInfo(const NativeCryptoInfo &cryptoInfo) {
+        if (cryptoInfo.mErr == OK) {
+            mNumSubSamples = cryptoInfo.mNumSubSamples;
+            mMode = cryptoInfo.mMode;
+            mPattern = cryptoInfo.mPattern;
+            if (cryptoInfo.mKey != nullptr) {
+                mKeyBuffer = ABuffer::CreateAsCopy(cryptoInfo.mKey, 16);
+                mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
+            }
+            if (cryptoInfo.mIv != nullptr) {
+               mIvBuffer = ABuffer::CreateAsCopy(cryptoInfo.mIv, 16);
+               mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
+            }
+            if (cryptoInfo.mSubSamples != nullptr) {
+                mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
+                if (mSubSamplesBuffer.get()) {
+                    CryptoPlugin::SubSample * samples =
+                            (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
+                    for (int s = 0 ; s < mNumSubSamples ; s++) {
+                        samples[s].mNumBytesOfClearData =
+                                cryptoInfo.mSubSamples[s].mNumBytesOfClearData;
+                        samples[s].mNumBytesOfEncryptedData =
+                                cryptoInfo.mSubSamples[s].mNumBytesOfEncryptedData;
+                    }
+                    mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
+                }
+            }
+
+        }
+    }
+
+    explicit MediaCodecCryptoInfo(jint size) {
+        mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * 1);
+        mNumSubSamples = 1;
+        if (mSubSamplesBuffer.get()) {
+            CryptoPlugin::SubSample * samples =
+                    (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
+            samples[0].mNumBytesOfClearData = size;
+            samples[0].mNumBytesOfEncryptedData = 0;
+            mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
+        }
+    }
+    ~MediaCodecCryptoInfo() {}
+
+protected:
+    // all backup buffers for the base object.
+    sp<ABuffer> mKeyBuffer;
+    sp<ABuffer> mIvBuffer;
+    sp<ABuffer> mSubSamplesBuffer;
+
+};
+
 static void android_media_MediaCodec_queueSecureInputBuffer(
         JNIEnv *env,
         jobject thiz,
@@ -2430,6 +2500,99 @@
             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
 }
 
+static status_t extractCryptoInfosFromObjectArray(JNIEnv * const env,
+        jint * const totalSize,
+        std::vector<std::unique_ptr<CodecCryptoInfo>> * const cryptoInfoObjs,
+        const jobjectArray &objArray,
+        AString * const errorDetailMsg) {
+    if (env == nullptr
+            || cryptoInfoObjs == nullptr
+            || totalSize == nullptr) {
+        if (errorDetailMsg) {
+            *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
+        }
+        return BAD_VALUE;
+    }
+    const jsize numEntries = env->GetArrayLength(objArray);
+    if (numEntries <= 0) {
+        if (errorDetailMsg) {
+            *errorDetailMsg = "Error: No CryptoInfo found while queuing for large frame input";
+        }
+        return BAD_VALUE;
+    }
+    cryptoInfoObjs->clear();
+    *totalSize = 0;
+    jint size = 0;
+    for (jsize i = 0; i < numEntries ; i++) {
+        jobject param = env->GetObjectArrayElement(objArray, i);
+        if (param == NULL) {
+            if (errorDetailMsg) {
+                *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
+            }
+            return BAD_VALUE;
+        }
+        NativeCryptoInfo nativeInfo(env, param);
+        std::unique_ptr<CodecCryptoInfo> info(new MediaCodecCryptoInfo(nativeInfo));
+        for (int i = 0; i < info->mNumSubSamples; i++) {
+            size += info->mSubSamples[i].mNumBytesOfClearData;
+            size += info->mSubSamples[i].mNumBytesOfEncryptedData;
+        }
+        cryptoInfoObjs->push_back(std::move(info));
+    }
+    *totalSize = size;
+    return OK;
+}
+
+
+static void android_media_MediaCodec_queueSecureInputBuffers(
+        JNIEnv *env,
+        jobject thiz,
+        jint index,
+        jobjectArray bufferInfosObjs,
+        jobjectArray cryptoInfoObjs) {
+    ALOGV("android_media_MediaCodec_queueSecureInputBuffers");
+
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+    if (codec == NULL || codec->initCheck() != OK) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
+        return;
+    }
+    sp<BufferInfosWrapper> auInfos =
+            new BufferInfosWrapper{decltype(auInfos->value)()};
+    sp<CryptoInfosWrapper> cryptoInfos =
+        new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
+    AString errorDetailMsg;
+    jint initialOffset = 0;
+    jint totalSize = 0;
+    status_t err = extractInfosFromObject(
+            env,
+            &initialOffset,
+            &totalSize,
+            &auInfos->value,
+            bufferInfosObjs,
+            &errorDetailMsg);
+    if (err == OK) {
+        err = extractCryptoInfosFromObjectArray(env,
+            &totalSize,
+            &cryptoInfos->value,
+            cryptoInfoObjs,
+            &errorDetailMsg);
+    }
+    if (err == OK) {
+        err = codec->queueSecureInputBuffers(
+                index,
+                initialOffset,
+                totalSize,
+                auInfos,
+                cryptoInfos,
+                &errorDetailMsg);
+    }
+    throwExceptionAsNecessary(
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
+}
+
 static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
     ALOGV("android_media_MediaCodec_mapHardwareBuffer");
     AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
@@ -2762,7 +2925,7 @@
 
 static void android_media_MediaCodec_native_queueLinearBlock(
         JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
-        jobject cryptoInfoObj, jobjectArray objArray, jobject keys, jobject values) {
+        jobjectArray cryptoInfoArray, jobjectArray objArray, jobject keys, jobject values) {
     ALOGV("android_media_MediaCodec_native_queueLinearBlock");
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -2780,8 +2943,8 @@
                 "error occurred while converting tunings from Java to native");
         return;
     }
-    jint totalSize;
-    jint initialOffset;
+    jint totalSize = 0;
+    jint initialOffset = 0;
     std::vector<AccessUnitInfo> infoVec;
     AString errorDetailMsg;
     err = extractInfosFromObject(env,
@@ -2832,8 +2995,19 @@
                     "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
             return;
         }
-        auto cryptoInfo =
-                cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{totalSize};
+        sp<CryptoInfosWrapper> cryptoInfos = new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
+        jint sampleSize = 0;
+        if (cryptoInfoArray != nullptr) {
+            extractCryptoInfosFromObjectArray(env,
+                    &sampleSize,
+                    &cryptoInfos->value,
+                    cryptoInfoArray,
+                    &errorDetailMsg);
+        } else {
+            sampleSize = totalSize;
+            std::unique_ptr<CodecCryptoInfo> cryptoInfo{new MediaCodecCryptoInfo(totalSize)};
+            cryptoInfos->value.push_back(std::move(cryptoInfo));
+        }
         if (env->ExceptionCheck()) {
             // Creation of cryptoInfo failed. Let the exception bubble up.
             return;
@@ -2842,11 +3016,9 @@
                 index,
                 memory,
                 initialOffset,
-                cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
-                (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
-                cryptoInfo.mMode,
-                cryptoInfo.mPattern,
+                sampleSize,
                 infos,
+                cryptoInfos,
                 tunings,
                 &errorDetailMsg);
         ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
@@ -3950,6 +4122,9 @@
     { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
       (void *)android_media_MediaCodec_queueSecureInputBuffer },
 
+    { "native_queueSecureInputBuffers", "(I[Ljava/lang/Object;[Ljava/lang/Object;)V",
+      (void *)android_media_MediaCodec_queueSecureInputBuffers },
+
     { "native_mapHardwareBuffer",
       "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
       (void *)android_media_MediaCodec_mapHardwareBuffer },
@@ -3957,7 +4132,7 @@
     { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
 
     { "native_queueLinearBlock",
-      "(ILandroid/media/MediaCodec$LinearBlock;Landroid/media/MediaCodec$CryptoInfo;"
+      "(ILandroid/media/MediaCodec$LinearBlock;[Ljava/lang/Object;"
       "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
       (void *)android_media_MediaCodec_native_queueLinearBlock },
 
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 02708ef..abb23f5 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -114,6 +114,14 @@
             uint32_t flags,
             AString *errorDetailMsg);
 
+    status_t queueSecureInputBuffers(
+            size_t index,
+            size_t offset,
+            size_t size,
+            const sp<RefBase> &auInfos,
+            const sp<RefBase> &cryptoInfos,
+            AString *errorDetailMsg);
+
     status_t queueBuffer(
             size_t index, const std::shared_ptr<C2Buffer> &buffer,
             const sp<RefBase> &infos, const sp<AMessage> &tunings,
@@ -123,13 +131,9 @@
             size_t index,
             const sp<hardware::HidlMemory> &buffer,
             size_t offset,
-            const CryptoPlugin::SubSample *subSamples,
-            size_t numSubSamples,
-            const uint8_t key[16],
-            const uint8_t iv[16],
-            CryptoPlugin::Mode mode,
-            const CryptoPlugin::Pattern &pattern,
+            size_t size,
             const sp<RefBase> &infos,
+            const sp<RefBase> &cryptoInfos,
             const sp<AMessage> &tunings,
             AString *errorDetailMsg);
 
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index d5b3c7d..ece8851 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -14,12 +14,20 @@
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
+    method @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerNfcVendorNciCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.NfcVendorNciCallback);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
+    method @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int sendVendorNciMessage(int, @IntRange(from=0, to=15) int, @IntRange(from=0) int, @NonNull byte[]);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
+    method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterNfcVendorNciCallback(@NonNull android.nfc.NfcAdapter.NfcVendorNciCallback);
     field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
+    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int MESSAGE_TYPE_COMMAND = 1; // 0x1
+    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3; // 0x3
+    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED = 2; // 0x2
+    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_REJECTED = 1; // 0x1
+    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_SUCCESS = 0; // 0x0
     field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
     field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
     field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe
@@ -33,6 +41,11 @@
     method public boolean onUnlockAttempted(android.nfc.Tag);
   }
 
+  @FlaggedApi("android.nfc.nfc_vendor_cmd") public static interface NfcAdapter.NfcVendorNciCallback {
+    method @FlaggedApi("android.nfc.nfc_vendor_cmd") public void onVendorNciNotification(@IntRange(from=9, to=15) int, int, @NonNull byte[]);
+    method @FlaggedApi("android.nfc.nfc_vendor_cmd") public void onVendorNciResponse(@IntRange(from=0, to=15) int, int, @NonNull byte[]);
+  }
+
 }
 
 package android.nfc.cardemulation {
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 85879ac..8fea5af 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -24,6 +24,7 @@
 import android.nfc.IAppCallback;
 import android.nfc.INfcAdapterExtras;
 import android.nfc.INfcControllerAlwaysOnListener;
+import android.nfc.INfcVendorNciCallback;
 import android.nfc.INfcTag;
 import android.nfc.INfcCardEmulation;
 import android.nfc.INfcFCardEmulation;
@@ -87,4 +88,7 @@
     boolean isObserveModeSupported();
     boolean setObserveMode(boolean enabled);
     void updateDiscoveryTechnology(IBinder b, int pollFlags, int listenFlags);
+    int sendVendorNciMessage(int mt, int gid, int oid, in byte[] payload);
+    void registerVendorExtensionCallback(in INfcVendorNciCallback callbacks);
+    void unregisterVendorExtensionCallback(in INfcVendorNciCallback callbacks);
 }
diff --git a/nfc/java/android/nfc/INfcVendorNciCallback.aidl b/nfc/java/android/nfc/INfcVendorNciCallback.aidl
new file mode 100644
index 0000000..821dc6f
--- /dev/null
+++ b/nfc/java/android/nfc/INfcVendorNciCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.nfc;
+
+/**
+ * @hide
+ */
+oneway interface INfcVendorNciCallback {
+    void onVendorResponseReceived(int gid, int oid, in byte[] payload);
+    void onVendorNotificationReceived(int gid, int oid, in byte[] payload);
+}
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 0791721..40bbe74 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -19,6 +19,7 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -75,6 +76,7 @@
     static final String TAG = "NFC";
 
     private final NfcControllerAlwaysOnListener mControllerAlwaysOnListener;
+    private final NfcVendorNciCallbackListener mNfcVendorNciCallbackListener;
 
     /**
      * Intent to start an activity when a tag with NDEF payload is discovered.
@@ -861,6 +863,7 @@
         mTagRemovedListener = null;
         mLock = new Object();
         mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService());
+        mNfcVendorNciCallbackListener = new NfcVendorNciCallbackListener(getService());
     }
 
     /**
@@ -2757,4 +2760,163 @@
             return false;
         }
     }
+
+    /**
+     * Vendor NCI command success.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+    public static final int SEND_VENDOR_NCI_STATUS_SUCCESS = 0;
+    /**
+     * Vendor NCI command rejected.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+    public static final int SEND_VENDOR_NCI_STATUS_REJECTED = 1;
+    /**
+     * Vendor NCI command corrupted.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+    public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED  = 2;
+    /**
+     * Vendor NCI command failed with unknown reason.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+    public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3;
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            SEND_VENDOR_NCI_STATUS_SUCCESS,
+            SEND_VENDOR_NCI_STATUS_REJECTED,
+            SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED,
+            SEND_VENDOR_NCI_STATUS_FAILED,
+    })
+    @interface SendVendorNciStatus {}
+
+    /**
+     * Message Type for NCI Command.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+    public static final int MESSAGE_TYPE_COMMAND = 1;
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            MESSAGE_TYPE_COMMAND,
+    })
+    @interface MessageType {}
+
+    /**
+     * Send Vendor specific Nci Messages with custom message type.
+     *
+     * The format of the NCI messages are defined in the NCI specification. The platform is
+     * responsible for fragmenting the payload if necessary.
+     *
+     * Note that mt (message type) is added at the beginning of method parameters as it is more
+     * distinctive than other parameters and was requested from vendor.
+     *
+     * @param mt message Type of the command
+     * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
+     *            the NCI specification
+     * @param oid opcode ID of the command. This is left to the OEM / vendor to decide
+     * @param payload containing vendor Nci message payload
+     * @return message send status
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public @SendVendorNciStatus int sendVendorNciMessage(@MessageType int mt,
+            @IntRange(from = 0, to = 15) int gid, @IntRange(from = 0) int oid,
+            @NonNull byte[] payload) {
+        Objects.requireNonNull(payload, "Payload must not be null");
+        try {
+            return sService.sendVendorNciMessage(mt, gid, oid, payload);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Register an {@link NfcVendorNciCallback} to listen for Nfc vendor responses and notifications
+     * <p>The provided callback will be invoked by the given {@link Executor}.
+     *
+     * <p>When first registering a callback, the callbacks's
+     * {@link NfcVendorNciCallback#onVendorNciCallBack(byte[])} is immediately invoked to
+     * notify the vendor notification.
+     *
+     * @param executor an {@link Executor} to execute given callback
+     * @param callback user implementation of the {@link NfcVendorNciCallback}
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public void registerNfcVendorNciCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull NfcVendorNciCallback callback) {
+        mNfcVendorNciCallbackListener.register(executor, callback);
+    }
+
+    /**
+     * Unregister the specified {@link NfcVendorNciCallback}
+     *
+     * <p>The same {@link NfcVendorNciCallback} object used when calling
+     * {@link #registerNfcVendorNciCallback(Executor, NfcVendorNciCallback)} must be used.
+     *
+     * <p>Callbacks are automatically unregistered when application process goes away
+     *
+     * @param callback user implementation of the {@link NfcVendorNciCallback}
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public void unregisterNfcVendorNciCallback(@NonNull NfcVendorNciCallback callback) {
+        mNfcVendorNciCallbackListener.unregister(callback);
+    }
+
+    /**
+     * Interface for receiving vendor NCI responses and notifications.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+    public interface NfcVendorNciCallback {
+        /**
+         * Invoked when a vendor specific NCI response is received.
+         *
+         * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
+         *            the NCI specification.
+         * @param oid opcode ID of the command. This is left to the OEM / vendor to decide.
+         * @param payload containing vendor Nci message payload.
+         */
+        @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+        void onVendorNciResponse(
+                @IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload);
+
+        /**
+         * Invoked when a vendor specific NCI notification is received.
+         *
+         * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
+         *            the NCI specification.
+         * @param oid opcode ID of the command. This is left to the OEM / vendor to decide.
+         * @param payload containing vendor Nci message payload.
+         */
+        @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
+        void onVendorNciNotification(
+                @IntRange(from = 9, to = 15) int gid, int oid, @NonNull byte[] payload);
+    }
 }
diff --git a/nfc/java/android/nfc/NfcVendorNciCallbackListener.java b/nfc/java/android/nfc/NfcVendorNciCallbackListener.java
new file mode 100644
index 0000000..742d75f
--- /dev/null
+++ b/nfc/java/android/nfc/NfcVendorNciCallbackListener.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.nfc;
+
+import android.annotation.NonNull;
+import android.nfc.NfcAdapter.NfcVendorNciCallback;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public final class NfcVendorNciCallbackListener extends INfcVendorNciCallback.Stub {
+    private static final String TAG = "Nfc.NfcVendorNciCallbacks";
+    private final INfcAdapter mAdapter;
+    private boolean mIsRegistered = false;
+    private final Map<NfcVendorNciCallback, Executor> mCallbackMap = new HashMap<>();
+
+    public NfcVendorNciCallbackListener(@NonNull INfcAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    public void register(@NonNull Executor executor, @NonNull NfcVendorNciCallback callback) {
+        synchronized (this) {
+            if (mCallbackMap.containsKey(callback)) {
+                return;
+            }
+            mCallbackMap.put(callback, executor);
+            if (!mIsRegistered) {
+                try {
+                    mAdapter.registerVendorExtensionCallback(this);
+                    mIsRegistered = true;
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to register adapter state callback");
+                    mCallbackMap.remove(callback);
+                    throw e.rethrowFromSystemServer();
+                }
+            }
+        }
+    }
+
+    public void unregister(@NonNull NfcVendorNciCallback callback) {
+        synchronized (this) {
+            if (!mCallbackMap.containsKey(callback) || !mIsRegistered) {
+                return;
+            }
+            if (mCallbackMap.size() == 1) {
+                try {
+                    mAdapter.unregisterVendorExtensionCallback(this);
+                    mIsRegistered = false;
+                    mCallbackMap.remove(callback);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to unregister AdapterStateCallback with service");
+                    throw e.rethrowFromSystemServer();
+                }
+            } else {
+                mCallbackMap.remove(callback);
+            }
+        }
+    }
+
+    @Override
+    public void onVendorResponseReceived(int gid, int oid, @NonNull byte[] payload)
+            throws RemoteException {
+        synchronized (this) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                for (NfcVendorNciCallback callback : mCallbackMap.keySet()) {
+                    Executor executor = mCallbackMap.get(callback);
+                    executor.execute(() -> callback.onVendorNciResponse(gid, oid, payload));
+                }
+            } catch (RuntimeException ex) {
+                throw ex;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @Override
+    public void onVendorNotificationReceived(int gid, int oid, @NonNull byte[] payload)
+            throws RemoteException {
+        synchronized (this) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                for (NfcVendorNciCallback callback : mCallbackMap.keySet()) {
+                    Executor executor = mCallbackMap.get(callback);
+                    executor.execute(() -> callback.onVendorNciNotification(gid, oid, payload));
+                }
+            } catch (RuntimeException ex) {
+                throw ex;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+}
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 11be905..cb1a542 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -62,3 +62,10 @@
     description: "Flag for NFC set discovery tech API"
     bug: "300351519"
 }
+
+flag {
+    name: "nfc_vendor_cmd"
+    namespace: "nfc"
+    description: "Enable NFC vendor command support"
+    bug: "289879306"
+}
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
index d256aea..b5cf011 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
@@ -33,12 +33,12 @@
 import android.os.Process;
 import android.os.SystemProperties;
 import android.provider.DeviceConfig;
+import android.sysprop.CrashRecoveryProperties;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.LongArrayQueue;
-import android.util.MathUtils;
 import android.util.Slog;
 import android.util.Xml;
 
@@ -128,18 +128,9 @@
 
     @VisibleForTesting
     static final int DEFAULT_BOOT_LOOP_TRIGGER_COUNT = 5;
+    @VisibleForTesting
     static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
 
-    // These properties track individual system server boot events, and are reset once the boot
-    // threshold is met, or the boot loop trigger window is exceeded between boot events.
-    private static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
-    private static final String PROP_RESCUE_BOOT_START = "sys.rescue_boot_start";
-
-    // These properties track multiple calls made to observers tracking boot loops. They are reset
-    // when the de-escalation window is exceeded between boot events.
-    private static final String PROP_BOOT_MITIGATION_WINDOW_START = "sys.boot_mitigation_start";
-    private static final String PROP_BOOT_MITIGATION_COUNT = "sys.boot_mitigation_count";
-
     private long mNumberOfNativeCrashPollsRemaining;
 
     private static final int DB_VERSION = 1;
@@ -1702,42 +1693,45 @@
             setCount(0);
         }
 
-        private int getCount() {
-            return SystemProperties.getInt(PROP_RESCUE_BOOT_COUNT, 0);
+        protected int getCount() {
+            return CrashRecoveryProperties.rescueBootCount().orElse(0);
         }
 
-        private void setCount(int count) {
-            SystemProperties.set(PROP_RESCUE_BOOT_COUNT, Integer.toString(count));
+        protected void setCount(int count) {
+            CrashRecoveryProperties.rescueBootCount(count);
         }
 
         public long getStart() {
-            return SystemProperties.getLong(PROP_RESCUE_BOOT_START, 0);
+            return CrashRecoveryProperties.rescueBootStart().orElse(0L);
         }
 
         public int getMitigationCount() {
-            return SystemProperties.getInt(PROP_BOOT_MITIGATION_COUNT, 0);
+            return CrashRecoveryProperties.bootMitigationCount().orElse(0);
         }
 
         public void setStart(long start) {
-            setPropertyStart(PROP_RESCUE_BOOT_START, start);
+            CrashRecoveryProperties.rescueBootStart(getStartTime(start));
         }
 
         public void setMitigationStart(long start) {
-            setPropertyStart(PROP_BOOT_MITIGATION_WINDOW_START, start);
+            CrashRecoveryProperties.bootMitigationStart(getStartTime(start));
         }
 
         public long getMitigationStart() {
-            return SystemProperties.getLong(PROP_BOOT_MITIGATION_WINDOW_START, 0);
+            return CrashRecoveryProperties.bootMitigationStart().orElse(0L);
         }
 
         public void setMitigationCount(int count) {
-            SystemProperties.set(PROP_BOOT_MITIGATION_COUNT, Integer.toString(count));
+            CrashRecoveryProperties.bootMitigationCount(count);
         }
 
-        public void setPropertyStart(String property, long start) {
+        private static long constrain(long amount, long low, long high) {
+            return amount < low ? low : (amount > high ? high : amount);
+        }
+
+        public long getStartTime(long start) {
             final long now = mSystemClock.uptimeMillis();
-            final long newStart = MathUtils.constrain(start, 0, now);
-            SystemProperties.set(property, Long.toString(newStart));
+            return constrain(start, 0, now);
         }
 
         public void saveMitigationCountToMetadata() {
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
index 5d03ef5..6766afc 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
@@ -37,6 +37,7 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.sysprop.CrashRecoveryProperties;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.ExceptionUtils;
@@ -75,12 +76,6 @@
  */
 public class RescueParty {
     @VisibleForTesting
-    static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
-    static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset";
-    static final String PROP_ATTEMPTING_REBOOT = "sys.attempting_reboot";
-    static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted";
-    static final String PROP_LAST_FACTORY_RESET_TIME_MS = "persist.sys.last_factory_reset";
-    @VisibleForTesting
     static final int LEVEL_NONE = 0;
     @VisibleForTesting
     static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
@@ -93,8 +88,6 @@
     @VisibleForTesting
     static final int LEVEL_FACTORY_RESET = 5;
     @VisibleForTesting
-    static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
-    @VisibleForTesting
     static final String TAG = "RescueParty";
     @VisibleForTesting
     static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
@@ -131,7 +124,7 @@
 
     private static boolean isDisabled() {
         // Check if we're explicitly enabled for testing
-        if (SystemProperties.getBoolean(PROP_ENABLE_RESCUE, false)) {
+        if (CrashRecoveryProperties.enableRescueParty().orElse(false)) {
             return false;
         }
 
@@ -177,11 +170,11 @@
     }
 
     static boolean isFactoryResetPropertySet() {
-        return SystemProperties.getBoolean(PROP_ATTEMPTING_FACTORY_RESET, false);
+        return CrashRecoveryProperties.attemptingFactoryReset().orElse(false);
     }
 
     static boolean isRebootPropertySet() {
-        return SystemProperties.getBoolean(PROP_ATTEMPTING_REBOOT, false);
+        return CrashRecoveryProperties.attemptingReboot().orElse(false);
     }
 
     /**
@@ -440,7 +433,7 @@
             case LEVEL_WARM_REBOOT:
                 // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
                 // when device shutting down.
-                SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true");
+                CrashRecoveryProperties.attemptingReboot(true);
                 runnable = () -> {
                     try {
                         PowerManager pm = context.getSystemService(PowerManager.class);
@@ -462,9 +455,9 @@
                 if (isRebootPropertySet()) {
                     break;
                 }
-                SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true");
+                CrashRecoveryProperties.attemptingFactoryReset(true);
                 long now = System.currentTimeMillis();
-                SystemProperties.set(PROP_LAST_FACTORY_RESET_TIME_MS, Long.toString(now));
+                CrashRecoveryProperties.lastFactoryResetTimeMs(now);
                 runnable = new Runnable() {
                     @Override
                     public void run() {
@@ -514,10 +507,10 @@
     private static void resetAllSettingsIfNecessary(Context context, int mode,
             int level) throws Exception {
         // No need to reset Settings again if they are already reset in the current level once.
-        if (SystemProperties.getInt(PROP_MAX_RESCUE_LEVEL_ATTEMPTED, LEVEL_NONE) >= level) {
+        if (CrashRecoveryProperties.maxRescueLevelAttempted().orElse(LEVEL_NONE) >= level) {
             return;
         }
-        SystemProperties.set(PROP_MAX_RESCUE_LEVEL_ATTEMPTED, Integer.toString(level));
+        CrashRecoveryProperties.maxRescueLevelAttempted(level);
         // Try our best to reset all settings possible, and once finished
         // rethrow any exception that we encountered
         Exception res = null;
@@ -732,7 +725,7 @@
          * Will return {@code false} if a factory reset was already offered recently.
          */
         private boolean shouldThrottleReboot() {
-            Long lastResetTime = SystemProperties.getLong(PROP_LAST_FACTORY_RESET_TIME_MS, 0);
+            Long lastResetTime = CrashRecoveryProperties.lastFactoryResetTimeMs().orElse(0L);
             long now = System.currentTimeMillis();
             long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG,
                     DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN);
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 50322f0..dd74a2a 100644
--- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -34,6 +34,7 @@
 import android.os.HandlerThread;
 import android.os.PowerManager;
 import android.os.SystemProperties;
+import android.sysprop.CrashRecoveryProperties;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -70,7 +71,6 @@
 final class RollbackPackageHealthObserver implements PackageHealthObserver {
     private static final String TAG = "RollbackPackageHealthObserver";
     private static final String NAME = "rollback-observer";
-    private static final String PROP_ATTEMPTING_REBOOT = "sys.attempting_reboot";
     private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
             | ApplicationInfo.FLAG_SYSTEM;
 
@@ -450,7 +450,7 @@
                 markStagedSessionHandled(rollback.getRollbackId());
                 // Wait for all pending staged sessions to get handled before rebooting.
                 if (isPendingStagedSessionsEmpty()) {
-                    SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true");
+                    CrashRecoveryProperties.attemptingReboot(true);
                     mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
                 }
             }
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 3adb882..e067a08 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -526,7 +526,7 @@
     </string-array>
 
     <!-- USB configuration values for Developer Settings.
-         These are lists of USB functions passed to the USB Manager to change USB configuraton.
+         These are lists of USB functions passed to the USB Manager to change USB configuration.
          This can be overridden by devices with additional USB configurations.
          Do not translate. -->
     <string-array name="usb_configuration_values" translatable="false">
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 967a36b..78cacec 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -39,7 +39,6 @@
 hyunyoungs@google.com
 ikateryna@google.com
 iyz@google.com
-jaggies@google.com
 jamesoleary@google.com
 jbolinger@google.com
 jdemeulenaere@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
index a601e9b..0b9f559 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
@@ -4,5 +4,4 @@
 galinap@google.com
 patrikf@google.com
 robhor@google.com
-sergeynv@google.com
 
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 2dda76e..2ed75d9 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -191,6 +191,7 @@
         "ImmutabilityAnnotation",
         "securebox",
         "net_flags_lib",
+        "core_os_flags_lib",
     ],
     javac_shard_size: 50,
     javacflags: [
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 5335cc3..89fb9ce 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -38,6 +38,7 @@
 per-file PackageWatchdog.java, RescueParty.java = file:/services/core/java/com/android/server/rollback/OWNERS
 per-file PinnerService.java = file:/apct-tests/perftests/OWNERS
 per-file RescueParty.java = shuc@google.com, ancr@google.com, harshitmahajan@google.com
+per-file SensitiveContentProtectionManagerService.java = file:/core/java/android/permission/OWNERS
 per-file SystemClockTime.java = file:/services/core/java/com/android/server/timedetector/OWNERS
 per-file SystemTimeZone.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS
 per-file TelephonyRegistry.java = file:/telephony/OWNERS
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 627a62e..34c3d7e 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -246,16 +246,6 @@
 
         @Override
         public void run() {
-            if (mGuid.isEmpty()) {
-                Slog.e(TAG, "adbwifi guid was not set");
-                return;
-            }
-            mPort = native_pairing_start(mGuid, mPairingCode);
-            if (mPort <= 0 || mPort > 65535) {
-                Slog.e(TAG, "Unable to start pairing server");
-                return;
-            }
-
             // Register the mdns service
             NsdServiceInfo serviceInfo = new NsdServiceInfo();
             serviceInfo.setServiceName(mServiceName);
@@ -288,6 +278,28 @@
             mHandler.sendMessage(message);
         }
 
+        @Override
+        public void start() {
+            /*
+             * If a user is fast enough to click cancel, native_pairing_cancel can be invoked
+             * while native_pairing_start is running which run the destruction of the object
+             * while it is being constructed. Here we start the pairing server on foreground
+             * Thread so native_pairing_cancel can never be called concurrently. Then we let
+             * the pairing server run on a background Thread.
+             */
+            if (mGuid.isEmpty()) {
+                Slog.e(TAG, "adbwifi guid was not set");
+                return;
+            }
+            mPort = native_pairing_start(mGuid, mPairingCode);
+            if (mPort <= 0) {
+                Slog.e(TAG, "Unable to start pairing server");
+                return;
+            }
+
+            super.start();
+        }
+
         public void cancelPairing() {
             native_pairing_cancel();
         }
diff --git a/services/core/java/com/android/server/am/OomConnection.java b/services/core/java/com/android/server/am/OomConnection.java
new file mode 100644
index 0000000..17a4ce5
--- /dev/null
+++ b/services/core/java/com/android/server/am/OomConnection.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.os.OomKillRecord;
+import android.util.Slog;
+
+/** Connection to the out-of-memory (OOM) events' file */
+public final class OomConnection {
+    private static final String TAG = "OomConnection";
+
+    /** Connection listener interface */
+    public interface OomConnectionListener {
+
+        /**
+         * Callback function to handle the newest OOM kills.
+         *
+         * @param oomKills List of oom kills received from `waitOom()`
+         */
+        void handleOomEvent(OomKillRecord[] oomKills);
+    }
+
+    private final OomConnectionListener mOomListener;
+
+    private final OomConnectionThread mOomConnectionThread;
+
+    private static native OomKillRecord[] waitOom();
+
+    public OomConnection(OomConnectionListener listener) {
+        mOomListener = listener;
+        mOomConnectionThread = new OomConnectionThread();
+        mOomConnectionThread.start();
+    }
+
+    private final class OomConnectionThread extends Thread {
+        public void run() {
+            while (true) {
+                OomKillRecord[] oom_kills = null;
+                try {
+                    oom_kills = waitOom();
+                    mOomListener.handleOomEvent(oom_kills);
+                } catch (RuntimeException e) {
+                    Slog.e(TAG, "failed waiting for OOM events: " + e);
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b8d2284..1ad85426 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -97,6 +97,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.OomKillRecord;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -412,6 +413,8 @@
 
     private static LmkdConnection sLmkdConnection = null;
 
+    private static OomConnection sOomConnection = null;
+
     private boolean mOomLevelsSet = false;
 
     private boolean mAppDataIsolationEnabled = false;
@@ -855,6 +858,21 @@
                     THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
             sKillThread.start();
             sKillHandler = new KillHandler(sKillThread.getLooper());
+            sOomConnection = new OomConnection(new OomConnection.OomConnectionListener() {
+                @Override
+                public void handleOomEvent(OomKillRecord[] oomKills) {
+                    for (OomKillRecord oomKill: oomKills) {
+                        synchronized (mProcLock) {
+                            noteAppKill(
+                                oomKill.getPid(),
+                                oomKill.getUid(),
+                                ApplicationExitInfo.REASON_LOW_MEMORY,
+                                ApplicationExitInfo.SUBREASON_OOM_KILL,
+                                "oom");
+                        }
+                    }
+                }
+            });
             sLmkdConnection = new LmkdConnection(sKillThread.getLooper().getQueue(),
                     new LmkdConnection.LmkdConnectionListener() {
                         @Override
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 7ff6d11..1420671 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -341,8 +341,10 @@
         mHasAboveClient = false;
         for (int i = mConnections.size() - 1; i >= 0; i--) {
             ConnectionRecord cr = mConnections.valueAt(i);
-            if (cr.binding.service.app.mServices != this
-                    && cr.hasFlag(Context.BIND_ABOVE_CLIENT)) {
+
+            final boolean isSameProcess = cr.binding.service.app != null
+                    && cr.binding.service.app.mServices == this;
+            if (!isSameProcess && cr.hasFlag(Context.BIND_ABOVE_CLIENT)) {
                 mHasAboveClient = true;
                 break;
             }
diff --git a/services/core/java/com/android/server/biometrics/OWNERS b/services/core/java/com/android/server/biometrics/OWNERS
index 1bf2aef..4703efb 100644
--- a/services/core/java/com/android/server/biometrics/OWNERS
+++ b/services/core/java/com/android/server/biometrics/OWNERS
@@ -2,7 +2,6 @@
 
 graciecheng@google.com
 ilyamaty@google.com
-jaggies@google.com
 jbolinger@google.com
 jeffpu@google.com
 joshmccloskey@google.com
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 2f9149a..dea5f82 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1336,6 +1336,11 @@
     }
 
     @Override // Binder call
+    public int getMousePointerSpeed() {
+        return mNative.getMousePointerSpeed();
+    }
+
+    @Override // Binder call
     public void tryPointerSpeed(int speed) {
         if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
                 "tryPointerSpeed()")) {
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 363bc94..79c042d 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -117,6 +117,8 @@
      */
     boolean transferTouch(IBinder destChannelToken, int displayId);
 
+    int getMousePointerSpeed();
+
     void setPointerSpeed(int speed);
 
     void setPointerAcceleration(float acceleration);
@@ -343,6 +345,9 @@
         public native boolean transferTouch(IBinder destChannelToken, int displayId);
 
         @Override
+        public native int getMousePointerSpeed();
+
+        @Override
         public native void setPointerSpeed(int speed);
 
         @Override
diff --git a/services/core/java/com/android/server/locksettings/OWNERS b/services/core/java/com/android/server/locksettings/OWNERS
index 5d49863..48da270 100644
--- a/services/core/java/com/android/server/locksettings/OWNERS
+++ b/services/core/java/com/android/server/locksettings/OWNERS
@@ -1,4 +1,3 @@
 # Bug component: 1333694
 ebiggers@google.com
-jaggies@google.com
 rubinxu@google.com
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OWNERS b/services/core/java/com/android/server/ondeviceintelligence/OWNERS
new file mode 100644
index 0000000..09774f7
--- /dev/null
+++ b/services/core/java/com/android/server/ondeviceintelligence/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/ondeviceintelligence/OWNERS
diff --git a/services/core/java/com/android/server/os/Android.bp b/services/core/java/com/android/server/os/Android.bp
new file mode 100644
index 0000000..565dc3b
--- /dev/null
+++ b/services/core/java/com/android/server/os/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+    name: "core_os_flags",
+    package: "com.android.server.os",
+    srcs: [
+        "*.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "core_os_flags_lib",
+    aconfig_declarations: "core_os_flags",
+}
diff --git a/services/core/java/com/android/server/os/core_os_flags.aconfig b/services/core/java/com/android/server/os/core_os_flags.aconfig
new file mode 100644
index 0000000..cbc0d54
--- /dev/null
+++ b/services/core/java/com/android/server/os/core_os_flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.os"
+
+flag {
+    name: "proto_tombstone"
+    namespace: "proto_tombstone_ns"
+    description: "Use proto tombstones as source of truth for adding to dropbox"
+    bug: "323857385"
+}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 988a32f..8e31e76 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -4331,7 +4331,7 @@
                                 + "; old: " + pkgSetting.getPathString() + " @ "
                                 + pkgSetting.getVersionCode()
                                 + "; new: " + parsedPackage.getPath() + " @ "
-                                + parsedPackage.getPath());
+                                + parsedPackage.getLongVersionCode());
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 7c307bd..57b89e3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -762,6 +762,24 @@
             }
         }
 
+        if (Flags.recoverabilityDetection()) {
+            if (params.rollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH
+                    || params.rollbackImpactLevel
+                    == PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) {
+                if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
+                    throw new IllegalArgumentException(
+                            "Can't set rollbackImpactLevel when rollback is not enabled");
+                }
+                if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException(
+                            "Setting rollbackImpactLevel requires the MANAGE_ROLLBACKS permission");
+                }
+            } else if (params.rollbackImpactLevel < 0) {
+                throw new IllegalArgumentException("rollbackImpactLevel can't be negative.");
+            }
+        }
+
         boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
         if (isApex) {
             if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 94c6b8b..fbd6526 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1207,6 +1207,7 @@
             info.autoRevokePermissionsMode = params.autoRevokePermissionsMode;
             info.installFlags = params.installFlags;
             info.rollbackLifetimeMillis = params.rollbackLifetimeMillis;
+            info.rollbackImpactLevel = params.rollbackImpactLevel;
             info.isMultiPackage = params.isMultiPackage;
             info.isStaged = params.isStaged;
             info.rollbackDataPolicy = params.rollbackDataPolicy;
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index a5b90f1..a580bb7 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -215,7 +215,8 @@
                 /* packages */ new ArrayList<>(),
                 /* isStaged */ isStaged,
                 /* causePackages */ new ArrayList<>(),
-                /* committedSessionId */ -1);
+                /* committedSessionId */ -1,
+                /* rollbackImpactLevel */ PackageManager.ROLLBACK_USER_IMPACT_LOW);
         mUserId = userId;
         mInstallerPackageName = installerPackageName;
         mBackupDir = backupDir;
@@ -394,7 +395,8 @@
      */
     @WorkerThread
     boolean enableForPackage(String packageName, long newVersion, long installedVersion,
-            boolean isApex, String sourceDir, String[] splitSourceDirs, int rollbackDataPolicy) {
+            boolean isApex, String sourceDir, String[] splitSourceDirs, int rollbackDataPolicy,
+            @PackageManager.RollbackImpactLevel int rollbackImpactLevel) {
         assertInWorkerThread();
         try {
             RollbackStore.backupPackageCodePath(this, packageName, sourceDir);
@@ -415,6 +417,10 @@
                 isApex, false /* isApkInApex */, new ArrayList<>(), rollbackDataPolicy);
 
         info.getPackages().add(packageRollbackInfo);
+
+        if (info.getRollbackImpactLevel() < rollbackImpactLevel) {
+            info.setRollbackImpactLevel(rollbackImpactLevel);
+        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index b38d6c7..d96fc33 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -954,7 +954,7 @@
         ApplicationInfo appInfo = pkgInfo.applicationInfo;
         return rollback.enableForPackage(packageName, newPackage.getVersionCode(),
                 pkgInfo.getLongVersionCode(), isApex, appInfo.sourceDir,
-                appInfo.splitSourceDirs, rollbackDataPolicy);
+                appInfo.splitSourceDirs, rollbackDataPolicy, session.rollbackImpactLevel);
     }
 
     @ExtThread
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 0af137f..14539d5 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -193,16 +193,27 @@
         json.put("isStaged", rollback.isStaged());
         json.put("causePackages", versionedPackagesToJson(rollback.getCausePackages()));
         json.put("committedSessionId", rollback.getCommittedSessionId());
+        if (Flags.recoverabilityDetection()) {
+            json.put("rollbackImpactLevel", rollback.getRollbackImpactLevel());
+        }
         return json;
     }
 
     private static RollbackInfo rollbackInfoFromJson(JSONObject json) throws JSONException {
-        return new RollbackInfo(
+        RollbackInfo rollbackInfo = new RollbackInfo(
                 json.getInt("rollbackId"),
                 packageRollbackInfosFromJson(json.getJSONArray("packages")),
                 json.getBoolean("isStaged"),
                 versionedPackagesFromJson(json.getJSONArray("causePackages")),
                 json.getInt("committedSessionId"));
+
+        if (Flags.recoverabilityDetection()) {
+                // to make it backward compatible.
+            rollbackInfo.setRollbackImpactLevel(json.optInt("rollbackImpactLevel",
+                    PackageManager.ROLLBACK_USER_IMPACT_LOW));
+        }
+
+        return rollbackInfo;
     }
 
     /**
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
index d5bc912..b69ccb3 100644
--- a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
+++ b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package com.android.server.security;
 
 import android.content.Context;
@@ -23,6 +22,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Binder;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 import android.security.keystore.IKeyAttestationApplicationIdProvider;
 import android.security.keystore.KeyAttestationApplicationId;
@@ -57,7 +57,10 @@
         try {
             String[] packageNames = mPackageManager.getPackagesForUid(uid);
             if (packageNames == null) {
-                throw new RemoteException("No packages for uid");
+                throw new ServiceSpecificException(
+                        IKeyAttestationApplicationIdProvider
+                                .ERROR_GET_ATTESTATION_APPLICATION_ID_FAILED,
+                        "No package for uid: " + uid);
             }
             int userId = UserHandle.getUserId(uid);
             keyAttestationPackageInfos = new KeyAttestationPackageInfo[packageNames.length];
diff --git a/services/core/java/com/android/server/selinux/OWNERS b/services/core/java/com/android/server/selinux/OWNERS
new file mode 100644
index 0000000..6ca4da2
--- /dev/null
+++ b/services/core/java/com/android/server/selinux/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1117393
+
+sandrom@google.com
diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java
index ed04e5f..1383708 100644
--- a/services/core/java/com/android/server/vcn/VcnContext.java
+++ b/services/core/java/com/android/server/vcn/VcnContext.java
@@ -34,7 +34,7 @@
     @NonNull private final Looper mLooper;
     @NonNull private final VcnNetworkProvider mVcnNetworkProvider;
     @NonNull private final FeatureFlags mFeatureFlags;
-    @NonNull private final com.android.net.flags.FeatureFlags mCoreNetFeatureFlags;
+    @NonNull private final android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags;
     private final boolean mIsInTestMode;
 
     public VcnContext(
@@ -49,7 +49,7 @@
 
         // Auto-generated class
         mFeatureFlags = new FeatureFlagsImpl();
-        mCoreNetFeatureFlags = new com.android.net.flags.FeatureFlagsImpl();
+        mCoreNetFeatureFlags = new android.net.platform.flags.FeatureFlagsImpl();
     }
 
     @NonNull
diff --git a/services/core/java/com/android/server/wm/WindowList.java b/services/core/java/com/android/server/wm/WindowList.java
index dfeba40..1e888f5 100644
--- a/services/core/java/com/android/server/wm/WindowList.java
+++ b/services/core/java/com/android/server/wm/WindowList.java
@@ -24,7 +24,7 @@
  */
 class WindowList<E> extends ArrayList<E> {
 
-    void addFirst(E e) {
+    public void addFirst(E e) {
         add(0, e);
     }
 
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 8cd55c7..1f6f4f3 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -77,6 +77,7 @@
         "onload.cpp",
         ":lib_cachedAppOptimizer_native",
         ":lib_gameManagerService_native",
+        ":lib_oomConnection_native",
     ],
 
     include_dirs: [
@@ -118,6 +119,7 @@
         "libhardware_legacy",
         "libhidlbase",
         "libmeminfo",
+        "libmemevents",
         "libmemtrackproxy",
         "libmtp",
         "libnativehelper",
@@ -235,3 +237,8 @@
         "com_android_server_app_GameManagerService.cpp",
     ],
 }
+
+filegroup {
+    name: "lib_oomConnection_native",
+    srcs: ["com_android_server_am_OomConnection.cpp"],
+}
diff --git a/services/core/jni/com_android_server_am_OomConnection.cpp b/services/core/jni/com_android_server_am_OomConnection.cpp
new file mode 100644
index 0000000..49a3ad3
--- /dev/null
+++ b/services/core/jni/com_android_server_am_OomConnection.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#define LOG_TAG "OomConnection"
+
+#include <core_jni_helpers.h>
+#include <jni.h>
+#include <memevents/memevents.h>
+
+namespace android {
+
+using namespace ::android::bpf::memevents;
+
+// Used to cache the results of the JNI name lookup
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+} sOomKillRecordInfo;
+
+static MemEventListener memevent_listener(MemEventClient::AMS);
+
+/**
+ * Initialize listening and waiting for new out-of-memory (OOM) events to occur.
+ * Once a OOM event is detected, we then fetch the list of OOM kills, and return
+ * a corresponding java array with the information gathered.
+ *
+ * In the case that we encounter an error, we make sure to close the epfd, and
+ * the OOM file descriptor, by calling `deregisterAllEvents()`.
+ *
+ * @return list of `android.os.OomKillRecord`
+ * @throws java.lang.RuntimeException
+ */
+static jobjectArray android_server_am_OomConnection_waitOom(JNIEnv* env, jobject) {
+    if (!memevent_listener.registerEvent(MEM_EVENT_OOM_KILL)) {
+        memevent_listener.deregisterAllEvents();
+        jniThrowRuntimeException(env, "listener failed to register to OOM events");
+        return nullptr;
+    }
+
+    if (!memevent_listener.listen()) {
+        memevent_listener.deregisterAllEvents();
+        jniThrowRuntimeException(env, "listener failed waiting for OOM event");
+        return nullptr;
+    }
+
+    std::vector<mem_event_t> oom_events;
+    if (!memevent_listener.getMemEvents(oom_events)) {
+        memevent_listener.deregisterAllEvents();
+        jniThrowRuntimeException(env, "Failed to get OOM events");
+        return nullptr;
+    }
+
+    jobjectArray java_oom_array =
+            env->NewObjectArray(oom_events.size(), sOomKillRecordInfo.clazz, nullptr);
+    if (java_oom_array == NULL) {
+        memevent_listener.deregisterAllEvents();
+        jniThrowRuntimeException(env, "Failed to create OomKillRecord array");
+        return nullptr;
+    }
+
+    for (int i = 0; i < oom_events.size(); i++) {
+        const mem_event_t mem_event = oom_events[i];
+        if (mem_event.type != MEM_EVENT_OOM_KILL) {
+            memevent_listener.deregisterAllEvents();
+            jniThrowRuntimeException(env, "Received invalid memory event");
+            return java_oom_array;
+        }
+
+        const auto oom_kill = mem_event.event_data.oom_kill;
+
+        jstring process_name = env->NewStringUTF(oom_kill.process_name);
+        if (process_name == NULL) {
+            memevent_listener.deregisterAllEvents();
+            jniThrowRuntimeException(env, "Failed creating java string for process name");
+        }
+        jobject java_oom_kill = env->NewObject(sOomKillRecordInfo.clazz, sOomKillRecordInfo.ctor,
+                                               oom_kill.timestamp_ms, oom_kill.pid, oom_kill.uid,
+                                               process_name, oom_kill.oom_score_adj);
+        if (java_oom_kill == NULL) {
+            memevent_listener.deregisterAllEvents();
+            jniThrowRuntimeException(env, "Failed to create OomKillRecord object");
+            return java_oom_array;
+        }
+        env->SetObjectArrayElement(java_oom_array, i, java_oom_kill);
+    }
+    return java_oom_array;
+}
+
+static const JNINativeMethod sOomConnectionMethods[] = {
+        /* name, signature, funcPtr */
+        {"waitOom", "()[Landroid/os/OomKillRecord;",
+         (void*)android_server_am_OomConnection_waitOom},
+};
+
+int register_android_server_am_OomConnection(JNIEnv* env) {
+    sOomKillRecordInfo.clazz = FindClassOrDie(env, "android/os/OomKillRecord");
+    sOomKillRecordInfo.clazz = MakeGlobalRefOrDie(env, sOomKillRecordInfo.clazz);
+
+    sOomKillRecordInfo.ctor =
+            GetMethodIDOrDie(env, sOomKillRecordInfo.clazz, "<init>", "(JIILjava/lang/String;S)V");
+
+    return RegisterMethodsOrDie(env, "com/android/server/am/OomConnection", sOomConnectionMethods,
+                                NELEM(sOomConnectionMethods));
+}
+} // namespace android
\ No newline at end of file
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9d39165..0af8169 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -290,6 +290,7 @@
     void setInputDispatchMode(bool enabled, bool frozen);
     void setSystemUiLightsOut(bool lightsOut);
     void setPointerDisplayId(int32_t displayId);
+    int32_t getMousePointerSpeed();
     void setPointerSpeed(int32_t speed);
     void setPointerAcceleration(float acceleration);
     void setTouchpadPointerSpeed(int32_t speed);
@@ -1096,6 +1097,11 @@
             InputReaderConfiguration::Change::DISPLAY_INFO);
 }
 
+int32_t NativeInputManager::getMousePointerSpeed() {
+    std::scoped_lock _l(mLock);
+    return mLocked.pointerSpeed;
+}
+
 void NativeInputManager::setPointerSpeed(int32_t speed) {
     { // acquire lock
         std::scoped_lock _l(mLock);
@@ -2037,6 +2043,12 @@
     }
 }
 
+static jint nativeGetMousePointerSpeed(JNIEnv* env, jobject nativeImplObj) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+
+    return static_cast<jint>(im->getMousePointerSpeed());
+}
+
 static void nativeSetPointerSpeed(JNIEnv* env, jobject nativeImplObj, jint speed) {
     NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
 
@@ -2633,6 +2645,7 @@
         {"transferTouchFocus", "(Landroid/os/IBinder;Landroid/os/IBinder;Z)Z",
          (void*)nativeTransferTouchFocus},
         {"transferTouch", "(Landroid/os/IBinder;I)Z", (void*)nativeTransferTouch},
+        {"getMousePointerSpeed", "()I", (void*)nativeGetMousePointerSpeed},
         {"setPointerSpeed", "(I)V", (void*)nativeSetPointerSpeed},
         {"setPointerAcceleration", "(F)V", (void*)nativeSetPointerAcceleration},
         {"setTouchpadPointerSpeed", "(I)V", (void*)nativeSetTouchpadPointerSpeed},
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index a87902f..cf0c55d 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -51,6 +51,7 @@
 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
 int register_android_server_SyntheticPasswordManager(JNIEnv* env);
 int register_android_hardware_display_DisplayViewport(JNIEnv* env);
+int register_android_server_am_OomConnection(JNIEnv* env);
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
 int register_android_server_am_LowMemDetector(JNIEnv* env);
 int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env);
@@ -110,6 +111,7 @@
     register_android_server_storage_AppFuse(env);
     register_android_server_SyntheticPasswordManager(env);
     register_android_hardware_display_DisplayViewport(env);
+    register_android_server_am_OomConnection(env);
     register_android_server_am_CachedAppOptimizer(env);
     register_android_server_am_LowMemDetector(env);
     register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env);
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 8f25c0d..cd18918 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -53,6 +53,7 @@
         "mockito-target-extended-minus-junit4",
         "platform-compat-test-rules",
         "platform-test-annotations",
+        "PlatformProperties",
         "service-blobstore",
         "service-jobscheduler",
         "service-permission.impl",
diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp
index f1dc1fa..1eb9888 100644
--- a/services/tests/mockingservicestests/jni/Android.bp
+++ b/services/tests/mockingservicestests/jni/Android.bp
@@ -22,6 +22,7 @@
     srcs: [
         ":lib_cachedAppOptimizer_native",
         ":lib_gameManagerService_native",
+        ":lib_oomConnection_native",
         "onload.cpp",
     ],
 
@@ -42,6 +43,7 @@
         "libgui",
         "libhidlbase",
         "liblog",
+        "libmemevents",
         "libmeminfo",
         "libnativehelper",
         "libprocessgroup",
diff --git a/services/tests/mockingservicestests/jni/onload.cpp b/services/tests/mockingservicestests/jni/onload.cpp
index 23ccb22..fb91051 100644
--- a/services/tests/mockingservicestests/jni/onload.cpp
+++ b/services/tests/mockingservicestests/jni/onload.cpp
@@ -26,6 +26,7 @@
 namespace android {
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
 int register_android_server_app_GameManagerService(JNIEnv* env);
+int register_android_server_am_OomConnection(JNIEnv* env);
 };
 
 using namespace android;
@@ -42,6 +43,7 @@
     ALOG_ASSERT(env, "Could not retrieve the env!");
     register_android_server_am_CachedAppOptimizer(env);
     register_android_server_app_GameManagerService(env);
+    register_android_server_am_OomConnection(env);
     return JNI_VERSION_1_4;
 }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/OWNERS b/services/tests/mockingservicestests/src/com/android/server/OWNERS
index c0f0ce0..b363f54 100644
--- a/services/tests/mockingservicestests/src/com/android/server/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/OWNERS
@@ -1,3 +1,4 @@
 per-file *Alarm* = file:/apex/jobscheduler/OWNERS
 per-file *AppStateTracker* = file:/apex/jobscheduler/OWNERS
 per-file *DeviceIdleController* = file:/apex/jobscheduler/OWNERS
+per-file SensitiveContentProtectionManagerServiceTest.java = file:/core/java/android/permission/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 7b771af..2d065e2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -45,6 +45,7 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.sysprop.CrashRecoveryProperties;
 import android.util.ArraySet;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -95,7 +96,6 @@
             "persist.device_config.configuration.disable_rescue_party";
     private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
             "persist.device_config.configuration.disable_rescue_party_factory_reset";
-    private static final String PROP_LAST_FACTORY_RESET_TIME_MS = "persist.sys.last_factory_reset";
 
     private static final int THROTTLING_DURATION_MIN = 10;
 
@@ -211,8 +211,8 @@
 
         doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime());
 
-        SystemProperties.set(RescueParty.PROP_RESCUE_BOOT_COUNT, Integer.toString(0));
-        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+        CrashRecoveryProperties.rescueBootCount(0);
+        CrashRecoveryProperties.enableRescueParty(true);
         SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
     }
 
@@ -255,7 +255,7 @@
         noteBoot(4);
         assertTrue(RescueParty.isRebootPropertySet());
 
-        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        CrashRecoveryProperties.attemptingReboot(false);
         noteBoot(5);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
@@ -280,7 +280,7 @@
         noteAppCrash(4, true);
         assertTrue(RescueParty.isRebootPropertySet());
 
-        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        CrashRecoveryProperties.attemptingReboot(false);
         noteAppCrash(5, true);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
@@ -438,7 +438,7 @@
             noteBoot(i + 1);
         }
         assertFalse(RescueParty.isFactoryResetPropertySet());
-        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        CrashRecoveryProperties.attemptingReboot(false);
         noteBoot(LEVEL_FACTORY_RESET + 1);
         assertTrue(RescueParty.isAttemptingFactoryReset());
         assertTrue(RescueParty.isFactoryResetPropertySet());
@@ -456,7 +456,7 @@
         noteBoot(mitigationCount++);
         assertFalse(RescueParty.isFactoryResetPropertySet());
         noteBoot(mitigationCount++);
-        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        CrashRecoveryProperties.attemptingReboot(false);
         noteBoot(mitigationCount + 1);
         assertTrue(RescueParty.isAttemptingFactoryReset());
         assertTrue(RescueParty.isFactoryResetPropertySet());
@@ -464,10 +464,10 @@
 
     @Test
     public void testThrottlingOnBootFailures() {
-        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        CrashRecoveryProperties.attemptingReboot(false);
         long now = System.currentTimeMillis();
         long beforeTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN - 1);
-        SystemProperties.set(PROP_LAST_FACTORY_RESET_TIME_MS, Long.toString(beforeTimeout));
+        CrashRecoveryProperties.lastFactoryResetTimeMs(beforeTimeout);
         for (int i = 1; i <= LEVEL_FACTORY_RESET; i++) {
             noteBoot(i);
         }
@@ -476,10 +476,10 @@
 
     @Test
     public void testThrottlingOnAppCrash() {
-        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        CrashRecoveryProperties.attemptingReboot(false);
         long now = System.currentTimeMillis();
         long beforeTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN - 1);
-        SystemProperties.set(PROP_LAST_FACTORY_RESET_TIME_MS, Long.toString(beforeTimeout));
+        CrashRecoveryProperties.lastFactoryResetTimeMs(beforeTimeout);
         for (int i = 0; i <= LEVEL_FACTORY_RESET; i++) {
             noteAppCrash(i + 1, true);
         }
@@ -488,10 +488,10 @@
 
     @Test
     public void testNotThrottlingAfterTimeoutOnBootFailures() {
-        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        CrashRecoveryProperties.attemptingReboot(false);
         long now = System.currentTimeMillis();
         long afterTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN + 1);
-        SystemProperties.set(PROP_LAST_FACTORY_RESET_TIME_MS, Long.toString(afterTimeout));
+        CrashRecoveryProperties.lastFactoryResetTimeMs(afterTimeout);
         for (int i = 1; i <= LEVEL_FACTORY_RESET; i++) {
             noteBoot(i);
         }
@@ -499,10 +499,10 @@
     }
     @Test
     public void testNotThrottlingAfterTimeoutOnAppCrash() {
-        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        CrashRecoveryProperties.attemptingReboot(false);
         long now = System.currentTimeMillis();
         long afterTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN + 1);
-        SystemProperties.set(PROP_LAST_FACTORY_RESET_TIME_MS, Long.toString(afterTimeout));
+        CrashRecoveryProperties.lastFactoryResetTimeMs(afterTimeout);
         for (int i = 0; i <= LEVEL_FACTORY_RESET; i++) {
             noteAppCrash(i + 1, true);
         }
@@ -525,26 +525,26 @@
 
     @Test
     public void testExplicitlyEnablingAndDisablingRescue() {
-        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
+        CrashRecoveryProperties.enableRescueParty(false);
         SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
         assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
                 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1), false);
 
-        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+        CrashRecoveryProperties.enableRescueParty(true);
         assertTrue(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
                 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1));
     }
 
     @Test
     public void testDisablingRescueByDeviceConfigFlag() {
-        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
+        CrashRecoveryProperties.enableRescueParty(false);
         SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(true));
 
         assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
                 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1), false);
 
         // Restore the property value initialized in SetUp()
-        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+        CrashRecoveryProperties.enableRescueParty(true);
         SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index 64cc397..9ba4f5b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -218,4 +218,9 @@
             assertEquals(errMsg, Thread.State.TERMINATED, getState());
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 2bc66ac..40b5458 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -1210,4 +1210,9 @@
             return returnValueForstartUserOnSecondaryDisplay;
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
index 1c0989c..9391d5b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
@@ -338,4 +338,8 @@
         }
     }
 
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index d56229c..e15942b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -1126,4 +1126,9 @@
             };
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
index 1fd7c4a..fa5bfd6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
@@ -284,4 +284,9 @@
 
         return app;
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
index 434d200..dfb8fda 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
@@ -803,4 +803,9 @@
             return mHandler;
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 0504344..732d0ce 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -2578,6 +2578,31 @@
         assertTrue(CACHED_APP_MAX_ADJ >= app3.mState.getSetAdj());
     }
 
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_AboveClient_NotStarted() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(app).when(sService).getTopApp();
+        sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+
+        assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
+
+        // Start binding to a service that isn't running yet.
+        ServiceRecord sr = makeServiceRecord(app);
+        sr.app = null;
+        bindService(null, app, sr, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+
+        // Since sr.app is null, this service cannot be in the same process as the
+        // client so we expect the BIND_ABOVE_CLIENT adjustment to take effect.
+        app.mServices.updateHasAboveClientLocked();
+        sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+        assertTrue(app.mServices.hasAboveClient());
+        assertNotEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
+    }
+
     private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
             String packageName, boolean hasShownUi) {
         long now = SystemClock.uptimeMillis();
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
index fd1b068..7ec27be 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
@@ -201,4 +201,9 @@
             return mActiveServices;
         }
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/selinux/OWNERS b/services/tests/mockingservicestests/src/com/android/server/selinux/OWNERS
new file mode 100644
index 0000000..49a0934
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/selinux/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/selinux/OWNERS
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 5cce1c2..92628f4 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -2,6 +2,13 @@
 // Build FrameworksServicesTests package
 //########################################################################
 
+java_defaults {
+    name: "FrameworksServicesTests-jni-defaults",
+    jni_libs: [
+        "libservicestestjni",
+    ],
+}
+
 package {
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
@@ -13,6 +20,9 @@
 
 android_test {
     name: "FrameworksServicesTests",
+    defaults: [
+        "FrameworksServicesTests-jni-defaults",
+    ],
 
     // Include all test java files.
     srcs: [
diff --git a/services/tests/servicestests/jni/Android.bp b/services/tests/servicestests/jni/Android.bp
new file mode 100644
index 0000000..174beb8
--- /dev/null
+++ b/services/tests/servicestests/jni/Android.bp
@@ -0,0 +1,58 @@
+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"],
+}
+
+cc_library_shared {
+    name: "libservicestestjni",
+
+    defaults: ["android.hardware.graphics.common-ndk_shared"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+
+    srcs: [
+        ":lib_cachedAppOptimizer_native",
+        ":lib_gameManagerService_native",
+        ":lib_oomConnection_native",
+        "onload.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/base/libs",
+        "frameworks/native/services",
+        "frameworks/native/libs/math/include",
+        "frameworks/native/libs/ui/include",
+        "system/memory/libmeminfo/include",
+    ],
+
+    shared_libs: [
+        "libandroid",
+        "libandroid_runtime",
+        "libbase",
+        "libbinder",
+        "libgralloctypes",
+        "libgui",
+        "libhidlbase",
+        "liblog",
+        "libmeminfo",
+        "libmemevents",
+        "libnativehelper",
+        "libprocessgroup",
+        "libutils",
+        "libcutils",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hidl.token@1.0-utils",
+    ],
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/jni/onload.cpp b/services/tests/servicestests/jni/onload.cpp
new file mode 100644
index 0000000..f160b3d
--- /dev/null
+++ b/services/tests/servicestests/jni/onload.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+/*
+ * this is a mini native libaray for cached app optimizer tests to run properly. It
+ * loads all the native methods necessary.
+ */
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+namespace android {
+int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
+int register_android_server_app_GameManagerService(JNIEnv* env);
+int register_android_server_am_OomConnection(JNIEnv* env);
+};
+
+using namespace android;
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
+{
+    JNIEnv* env = NULL;
+    jint result = -1;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        ALOGE("GetEnv failed!");
+        return result;
+    }
+    ALOG_ASSERT(env, "Could not retrieve the env!");
+    register_android_server_am_CachedAppOptimizer(env);
+    register_android_server_app_GameManagerService(env);
+    register_android_server_am_OomConnection(env);
+    return JNI_VERSION_1_4;
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
index acdfee9..c0051c6 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
@@ -172,4 +172,9 @@
                 anyString(), any(), any(), any(), anyBoolean(), any(), eq(mAuxExecutorService),
                 anyBoolean(), anyBoolean(), any());
     }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("servicestestjni");
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
index 9d56a36..5e11e17 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.pm.PackageManager;
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
 import android.util.SparseIntArray;
@@ -81,7 +82,8 @@
             + "'installedUsers':[55,79],"
             + "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello',"
             + "'longVersionCode':23},{'packageName':'something','longVersionCode':999}],"
-            + "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z',"
+            + "'committedSessionId':45654465, 'rollbackImpactLevel':1},"
+            + "'timestamp':'2019-10-01T12:29:08.855Z',"
             + "'originalSessionId':567,'state':'enabling','apkSessionId':-1,"
             + "'restoreUserDataInProgress':true, 'userId':0,"
             + "'installerPackageName':'some.installer'}";
@@ -138,6 +140,8 @@
         assertThat(rollback.getOriginalSessionId()).isEqualTo(567);
         assertThat(rollback.info.getRollbackId()).isEqualTo(ID);
         assertThat(rollback.info.getPackages()).isEmpty();
+        assertThat(rollback.info.getRollbackImpactLevel()).isEqualTo(
+                PackageManager.ROLLBACK_USER_IMPACT_LOW);
         assertThat(rollback.isEnabling()).isTrue();
         assertThat(rollback.getExtensionVersions().toString())
                 .isEqualTo(extensionVersions.toString());
@@ -158,6 +162,8 @@
 
         assertThat(rollback.info.getRollbackId()).isEqualTo(ID);
         assertThat(rollback.info.getPackages()).isEmpty();
+        assertThat(rollback.info.getRollbackImpactLevel()).isEqualTo(
+                PackageManager.ROLLBACK_USER_IMPACT_LOW);
         assertThat(rollback.isEnabling()).isTrue();
         assertThat(rollback.getExtensionVersions().toString())
                 .isEqualTo(extensionVersions.toString());
@@ -175,6 +181,7 @@
         origRb.info.getCausePackages().add(new VersionedPackage("com.made.up", 2));
         origRb.info.getCausePackages().add(new VersionedPackage("com.pack.age", 99));
         origRb.info.setCommittedSessionId(123456);
+        origRb.info.setRollbackImpactLevel(PackageManager.ROLLBACK_USER_IMPACT_HIGH);
 
         PackageRollbackInfo pkgInfo1 =
                 new PackageRollbackInfo(new VersionedPackage("com.made.up", 18),
@@ -226,6 +233,7 @@
         expectedRb.info.getCausePackages().add(new VersionedPackage("hello", 23));
         expectedRb.info.getCausePackages().add(new VersionedPackage("something", 999));
         expectedRb.info.setCommittedSessionId(45654465);
+        expectedRb.info.setRollbackImpactLevel(PackageManager.ROLLBACK_USER_IMPACT_HIGH);
 
         PackageRollbackInfo pkgInfo1 = new PackageRollbackInfo(new VersionedPackage("blah", 55),
                 new VersionedPackage("blah1", 50), new ArrayList<>(), new ArrayList<>(),
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
index c62db1ea..13b5f0d 100644
--- a/tests/Input/AndroidTest.xml
+++ b/tests/Input/AndroidTest.xml
@@ -4,6 +4,7 @@
  -->
 <configuration description="Runs Input Tests">
     <option name="test-tag" value="InputTests" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
         <!-- keeps the screen on during tests -->
         <option name="screen-always-on" value="on" />
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index d7fa124..755636a 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -70,6 +70,7 @@
 
 import java.io.File;
 import java.io.FileOutputStream;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -107,10 +108,13 @@
     private ConnectivityModuleConnector mConnectivityModuleConnector;
     @Mock
     private PackageManager mMockPackageManager;
+    // 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;
 
     private boolean retry(Supplier<Boolean> supplier) throws Exception {
         for (int i = 0; i < RETRY_MAX_COUNT; ++i) {
@@ -1416,6 +1420,8 @@
         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) {
@@ -1432,6 +1438,71 @@
         return watchdog;
     }
 
+    // Mock CrashRecoveryProperties as they cannot be accessed due to SEPolicy restrictions
+    private void mockCrashRecoveryProperties(PackageWatchdog watchdog) {
+        try {
+            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 -> {
+                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 static class TestObserver implements PackageHealthObserver {
         private final String mName;
         private int mImpact;
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index cbdcb88..518183f 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -30,6 +30,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
 import android.os.UserManager;
@@ -146,7 +147,8 @@
             assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
 
             // Upgrade from v1 to v2, with rollbacks enabled.
-            Install.single(TestApp.A2).setEnableRollback().commit();
+            Install.single(TestApp.A2).setEnableRollback().setRollbackImpactLevel(
+                    PackageManager.ROLLBACK_USER_IMPACT_HIGH).commit();
             assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             // The app should now be available for rollback.
@@ -154,6 +156,8 @@
             assertThat(available).isNotStaged();
             assertThat(available).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
+            assertThat(available.getRollbackImpactLevel()).isEqualTo(
+                    PackageManager.ROLLBACK_USER_IMPACT_HIGH);
 
             // We should not have received any rollback requests yet.
             // TODO: Possibly flaky if, by chance, some other app on device
@@ -264,6 +268,8 @@
             RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
             assertThat(rollbackB).packagesContainsExactly(
                     Rollback.from(TestApp.B2).to(TestApp.B1));
+            assertThat(rollbackB.getRollbackImpactLevel()).isEqualTo(
+                    PackageManager.ROLLBACK_USER_IMPACT_LOW);
 
             // Register rollback committed receiver
             RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver();
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 6015e931..381c574 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
@@ -101,7 +101,7 @@
     @Mock protected Context mContext;
     @Mock protected Network mNetwork;
     @Mock protected FeatureFlags mFeatureFlags;
-    @Mock protected com.android.net.flags.FeatureFlags mCoreNetFeatureFlags;
+    @Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags;
     @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot;
     @Mock protected TelephonyManager mTelephonyManager;
     @Mock protected IPowerManager mPowerManagerService;
diff --git a/tools/protologtool/OWNERS b/tools/protologtool/OWNERS
new file mode 100644
index 0000000..18cf2be
--- /dev/null
+++ b/tools/protologtool/OWNERS
@@ -0,0 +1,3 @@
+# ProtoLog owners
+# Bug component: 1157642
+include platform/development:/tools/winscope/OWNERS
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 3c55237..ce856cd 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -25,6 +25,7 @@
 import java.io.FileInputStream
 import java.io.FileOutputStream
 import java.io.OutputStream
+import java.time.LocalDateTime
 import java.util.concurrent.ExecutorService
 import java.util.concurrent.Executors
 import java.util.jar.JarOutputStream
@@ -42,6 +43,13 @@
         return source.contains(protoLogSimpleClassName)
     }
 
+    private fun zipEntry(path: String): ZipEntry {
+        val entry = ZipEntry(path)
+        // Use a constant time to improve the cachability of build actions.
+        entry.timeLocal = LocalDateTime.of(2008, 1, 1, 0, 0, 0)
+        return entry
+    }
+
     private fun processClasses(command: CommandOptions) {
         val groups = injector.readLogGroups(
                 command.protoLogGroupsJarArg,
@@ -77,7 +85,7 @@
                 }
             }.map { future ->
                 val (path, outSrc) = future.get()
-                outJar.putNextEntry(ZipEntry(path))
+                outJar.putNextEntry(zipEntry(path))
                 outJar.write(outSrc.toByteArray())
                 outJar.closeEntry()
             }
@@ -90,7 +98,7 @@
         val cachePackage = cacheSplit.dropLast(1).joinToString(".")
         val cachePath = "gen/${cacheSplit.joinToString("/")}.java"
 
-        outJar.putNextEntry(ZipEntry(cachePath))
+        outJar.putNextEntry(zipEntry(cachePath))
         outJar.write(generateLogGroupCache(cachePackage, cacheName, groups,
                 command.protoLogImplClassNameArg, command.protoLogGroupsClassNameArg).toByteArray())