Merge changes from topic "revert-26228978-device-state-callbacks-XJADFJXEAY" into main

* changes:
  Revert "Promote DeviceStateManager to System API and update Devi..."
  Revert "Creates DeviceState objects with display properties"
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index f819f15..bd00c03 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3852,7 +3852,7 @@
                     // the other jobs that will use this network.
                     if (DEBUG) {
                         Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: piggybacking "
-                                + batchedJobs.size() + " jobs on " + network
+                                + (batchedJobs.size() - unbatchedJobCount) + " jobs on " + network
                                 + " because of unbatched job");
                     }
                     jobsToRun.addAll(batchedJobs);
@@ -3892,8 +3892,12 @@
                     // Some job is going to use the CPU anyway. Might as well run all the other
                     // CPU-only jobs.
                     if (DEBUG) {
+                        final Integer unbatchedJobCountObj = mUnbatchedJobCount.get(null);
+                        final int unbatchedJobCount =
+                                unbatchedJobCountObj == null ? 0 : unbatchedJobCountObj;
                         Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: piggybacking "
-                                + batchedNonNetworkedJobs.size() + " non-network jobs");
+                                + (batchedNonNetworkedJobs.size() - unbatchedJobCount)
+                                + " non-network jobs");
                     }
                     jobsToRun.addAll(batchedNonNetworkedJobs);
                 } else if (batchedNonNetworkedJobs.size() >= minReadyCount) {
diff --git a/boot/hiddenapi/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
index 26dc700..adcc3df 100644
--- a/boot/hiddenapi/hiddenapi-unsupported.txt
+++ b/boot/hiddenapi/hiddenapi-unsupported.txt
@@ -133,8 +133,6 @@
 Landroid/hardware/location/IContextHubService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/location/IContextHubService;
 Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/location/ICountryListener$Stub;-><init>()V
-Landroid/location/IGeocodeProvider$Stub;-><init>()V
-Landroid/location/IGeocodeProvider$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/IGeocodeProvider;
 Landroid/location/ILocationListener$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/location/ILocationListener$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Landroid/location/ILocationListener$Stub;-><init>()V
diff --git a/core/api/current.txt b/core/api/current.txt
index ec8699a..6c56c19 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -144,10 +144,12 @@
     field public static final String MANAGE_DEVICE_POLICY_AUDIO_OUTPUT = "android.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT";
     field public static final String MANAGE_DEVICE_POLICY_AUTOFILL = "android.permission.MANAGE_DEVICE_POLICY_AUTOFILL";
     field public static final String MANAGE_DEVICE_POLICY_BACKUP_SERVICE = "android.permission.MANAGE_DEVICE_POLICY_BACKUP_SERVICE";
+    field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL = "android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL";
     field public static final String MANAGE_DEVICE_POLICY_BLUETOOTH = "android.permission.MANAGE_DEVICE_POLICY_BLUETOOTH";
     field public static final String MANAGE_DEVICE_POLICY_BUGREPORT = "android.permission.MANAGE_DEVICE_POLICY_BUGREPORT";
     field public static final String MANAGE_DEVICE_POLICY_CALLS = "android.permission.MANAGE_DEVICE_POLICY_CALLS";
     field public static final String MANAGE_DEVICE_POLICY_CAMERA = "android.permission.MANAGE_DEVICE_POLICY_CAMERA";
+    field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_CAMERA_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE";
     field public static final String MANAGE_DEVICE_POLICY_CERTIFICATES = "android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES";
     field public static final String MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE = "android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE";
     field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final String MANAGE_DEVICE_POLICY_CONTENT_PROTECTION = "android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION";
@@ -169,6 +171,7 @@
     field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS = "android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS";
     field public static final String MANAGE_DEVICE_POLICY_METERED_DATA = "android.permission.MANAGE_DEVICE_POLICY_METERED_DATA";
     field public static final String MANAGE_DEVICE_POLICY_MICROPHONE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE";
+    field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE";
     field public static final String MANAGE_DEVICE_POLICY_MOBILE_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK";
     field public static final String MANAGE_DEVICE_POLICY_MODIFY_USERS = "android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS";
     field public static final String MANAGE_DEVICE_POLICY_MTE = "android.permission.MANAGE_DEVICE_POLICY_MTE";
@@ -454,6 +457,7 @@
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
     field public static final int allowClickWhenDisabled = 16844312; // 0x1010618
+    field @FlaggedApi("android.security.asm_restrictions_enabled") public static final int allowCrossUidActivitySwitchFromBelow;
     field public static final int allowEmbedded = 16843765; // 0x10103f5
     field public static final int allowGameAngleDriver = 16844376; // 0x1010658
     field public static final int allowGameDownscaling = 16844377; // 0x1010659
@@ -687,6 +691,7 @@
     field public static final int defaultHeight = 16844021; // 0x10104f5
     field @FlaggedApi("android.content.res.default_locale") public static final int defaultLocale;
     field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
+    field @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") public static final int defaultToObserveMode;
     field public static final int defaultValue = 16843245; // 0x10101ed
     field public static final int defaultWidth = 16844020; // 0x10104f4
     field public static final int delay = 16843212; // 0x10101cc
@@ -1491,6 +1496,7 @@
     field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int sharedUserMaxSdkVersion = 16844365; // 0x101064d
     field public static final int shell = 16844180; // 0x1010594
+    field @FlaggedApi("com.android.text.flags.use_bounds_for_width") public static final int shiftDrawingOffsetForStartOverhang;
     field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
     field public static final int shortcutId = 16844072; // 0x1010528
     field public static final int shortcutLongLabel = 16844074; // 0x101052a
@@ -5459,11 +5465,15 @@
     method public int getDeferralPolicy();
     method @Nullable public String getDeliveryGroupMatchingKey();
     method public int getDeliveryGroupPolicy();
+    method @FlaggedApi("android.app.bcast_event_timestamps") public long getEventTriggerTimestampMillis();
+    method @FlaggedApi("android.app.bcast_event_timestamps") public long getRemoteEventTriggerTimestampMillis();
     method public boolean isShareIdentityEnabled();
     method @NonNull public static android.app.BroadcastOptions makeBasic();
     method @NonNull public android.app.BroadcastOptions setDeferralPolicy(int);
     method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String, @NonNull String);
     method @NonNull public android.app.BroadcastOptions setDeliveryGroupPolicy(int);
+    method @FlaggedApi("android.app.bcast_event_timestamps") public void setEventTriggerTimestampMillis(long);
+    method @FlaggedApi("android.app.bcast_event_timestamps") public void setRemoteEventTriggerTimestampMillis(long);
     method @NonNull public android.app.BroadcastOptions setShareIdentityEnabled(boolean);
     method @NonNull public android.os.Bundle toBundle();
     field public static final int DEFERRAL_POLICY_DEFAULT = 0; // 0x0
@@ -8113,6 +8123,7 @@
     method public boolean isLogoutEnabled();
     method public boolean isManagedProfile(@NonNull android.content.ComponentName);
     method public boolean isMasterVolumeMuted(@NonNull android.content.ComponentName);
+    method @FlaggedApi("android.app.admin.flags.is_mte_policy_enforced") public static boolean isMtePolicyEnforced();
     method public boolean isNetworkLoggingEnabled(@Nullable android.content.ComponentName);
     method public boolean isOrganizationOwnedDeviceWithManagedProfile();
     method public boolean isOverrideApnEnabled(@NonNull android.content.ComponentName);
@@ -20002,11 +20013,14 @@
 
   public final class ExtensionSessionConfiguration {
     ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback);
+    method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void clearColorSpace();
+    method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") @Nullable public android.graphics.ColorSpace getColorSpace();
     method @NonNull public java.util.concurrent.Executor getExecutor();
     method public int getExtension();
     method @NonNull public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
     method @Nullable public android.hardware.camera2.params.OutputConfiguration getPostviewOutputConfiguration();
     method @NonNull public android.hardware.camera2.CameraExtensionSession.StateCallback getStateCallback();
+    method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
     method public void setPostviewOutputConfiguration(@Nullable android.hardware.camera2.params.OutputConfiguration);
   }
 
@@ -22731,7 +22745,6 @@
 
   public final class MediaCodec.QueueRequest {
     method public void queue();
-    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setBufferInfos(@NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
     method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
     method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @NonNull android.media.MediaCodec.CryptoInfo);
     method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
@@ -22741,6 +22754,7 @@
     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 @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setMultiFrameLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
     method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
     method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
   }
@@ -22749,12 +22763,16 @@
     method @NonNull public String getCanonicalName();
     method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(String);
     method @NonNull public String getName();
+    method @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public int getSecurityModel();
     method public String[] getSupportedTypes();
     method public boolean isAlias();
     method public boolean isEncoder();
     method public boolean isHardwareAccelerated();
     method public boolean isSoftwareOnly();
     method public boolean isVendor();
+    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_MEMORY_SAFE = 1; // 0x1
+    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_SANDBOXED = 0; // 0x0
+    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2; // 0x2
   }
 
   public static final class MediaCodecInfo.AudioCapabilities {
@@ -23583,6 +23601,9 @@
     field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
     field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
     field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
+    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_MEMORY_SAFE = 2; // 0x2
+    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_SANDBOXED = 1; // 0x1
+    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 4; // 0x4
     field public static final String KEY_AAC_DRC_ALBUM_MODE = "aac-drc-album-mode";
     field public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
     field public static final String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
@@ -23664,6 +23685,7 @@
     field public static final String KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
     field public static final String KEY_ROTATION = "rotation-degrees";
     field public static final String KEY_SAMPLE_RATE = "sample-rate";
+    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final String KEY_SECURITY_MODEL = "security-model";
     field public static final String KEY_SLICE_HEIGHT = "slice-height";
     field public static final String KEY_SLOW_MOTION_MARKERS = "slow-motion-markers";
     field public static final String KEY_STRIDE = "stride";
@@ -42390,6 +42412,7 @@
     field public static final int SUPPORTS_SET_INACTIVE = 2; // 0x2
     field public static final int SUPPORTS_STREAM = 4; // 0x4
     field public static final int SUPPORTS_TRANSFER = 8; // 0x8
+    field @FlaggedApi("com.android.server.telecom.flags.transactional_video_state") public static final int SUPPORTS_VIDEO_CALLING = 16; // 0x10
     field public static final int VIDEO_CALL = 2; // 0x2
   }
 
@@ -42425,6 +42448,7 @@
     method @NonNull public android.os.ParcelUuid getCallId();
     method public void requestCallEndpointChange(@NonNull android.telecom.CallEndpoint, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
     method @FlaggedApi("com.android.server.telecom.flags.set_mute_state") public void requestMuteState(boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
+    method @FlaggedApi("com.android.server.telecom.flags.transactional_video_state") public void requestVideoState(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
     method public void sendEvent(@NonNull String, @NonNull android.os.Bundle);
     method public void setActive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
     method public void setInactive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
@@ -42473,6 +42497,7 @@
     method public void onCallStreamingFailed(int);
     method public void onEvent(@NonNull String, @NonNull android.os.Bundle);
     method public void onMuteStateChanged(boolean);
+    method @FlaggedApi("com.android.server.telecom.flags.transactional_video_state") public default void onVideoStateChanged(int);
   }
 
   public final class CallException extends java.lang.RuntimeException implements android.os.Parcelable {
@@ -47526,6 +47551,7 @@
     method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.text.DynamicLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
     method @NonNull public android.text.DynamicLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
     method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.DynamicLayout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
+    method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.DynamicLayout.Builder setShiftDrawingOffsetForStartOverhang(boolean);
     method @NonNull public android.text.DynamicLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
     method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.DynamicLayout.Builder setUseBoundsForWidth(boolean);
     method @NonNull public android.text.DynamicLayout.Builder setUseLineSpacingFromFallbacks(boolean);
@@ -47729,6 +47755,7 @@
     method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @Nullable public final int[] getRightIndents();
     method public float getSecondaryHorizontal(int);
     method public void getSelectionPath(int, int, android.graphics.Path);
+    method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public boolean getShiftDrawingOffsetForStartOverhang();
     method public final float getSpacingAdd();
     method public final float getSpacingMultiplier();
     method @NonNull public final CharSequence getText();
@@ -47785,6 +47812,7 @@
     method @NonNull public android.text.Layout.Builder setMaxLines(@IntRange(from=1) int);
     method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.Layout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
     method @NonNull public android.text.Layout.Builder setRightIndents(@Nullable int[]);
+    method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.Layout.Builder setShiftDrawingOffsetForStartOverhang(boolean);
     method @NonNull public android.text.Layout.Builder setTextDirectionHeuristic(@NonNull android.text.TextDirectionHeuristic);
     method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.Layout.Builder setUseBoundsForWidth(boolean);
   }
@@ -48056,6 +48084,7 @@
     method @NonNull public android.text.StaticLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
     method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int);
     method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.StaticLayout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
+    method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.StaticLayout.Builder setShiftDrawingOffsetForStartOverhang(boolean);
     method public android.text.StaticLayout.Builder setText(CharSequence);
     method @NonNull public android.text.StaticLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
     method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.StaticLayout.Builder setUseBoundsForWidth(boolean);
@@ -50565,7 +50594,6 @@
     method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
     method public default void setChildBoundingInsets(@NonNull android.graphics.Rect);
     method public default void setTouchableRegion(@Nullable android.graphics.Region);
-    method @FlaggedApi("com.android.window.flags.transfer_gesture_to_embedded") public default boolean transferHostTouchGestureToEmbedded(@NonNull android.view.SurfaceControlViewHost.SurfacePackage);
   }
 
   @UiThread public static interface AttachedSurfaceControl.OnBufferTransformHintChangedListener {
@@ -52283,6 +52311,7 @@
   public static final class SurfaceControlViewHost.SurfacePackage implements android.os.Parcelable {
     ctor public SurfaceControlViewHost.SurfacePackage(@NonNull android.view.SurfaceControlViewHost.SurfacePackage);
     method public int describeContents();
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @Nullable public android.window.InputTransferToken getInputTransferToken();
     method @NonNull public android.view.SurfaceControl getSurfaceControl();
     method public void notifyConfigurationChanged(@NonNull android.content.res.Configuration);
     method public void notifyDetachedFromWindow();
@@ -53243,7 +53272,7 @@
     field protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
     field protected static final int[] PRESSED_STATE_SET;
     field protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET;
-    field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = 0.0f;
+    field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = (0.0f/0.0f);
     field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_HIGH = -4.0f;
     field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_LOW = -2.0f;
     field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_NORMAL = -3.0f;
@@ -54418,15 +54447,17 @@
     method @Deprecated public android.view.Display getDefaultDisplay();
     method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
     method public default boolean isCrossWindowBlurEnabled();
-    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerBatchedSurfaceControlInputReceiver(int, @NonNull android.window.InputTransferToken, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.window.InputTransferToken registerBatchedSurfaceControlInputReceiver(int, @NonNull android.window.InputTransferToken, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
     method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void registerTrustedPresentationListener(@NonNull android.os.IBinder, @NonNull android.window.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
-    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.window.InputTransferToken, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.window.InputTransferToken registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.window.InputTransferToken, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
     method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer);
     method @FlaggedApi("com.android.window.flags.screen_recording_callbacks") @RequiresPermission(android.Manifest.permission.DETECT_SCREEN_RECORDING) public default void removeScreenRecordingCallback(@NonNull java.util.function.Consumer<java.lang.Integer>);
     method public void removeViewImmediate(android.view.View);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default boolean transferTouchGesture(@NonNull android.window.InputTransferToken, @NonNull android.window.InputTransferToken);
     method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void unregisterSurfaceControlInputReceiver(@NonNull android.view.SurfaceControl);
     method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void unregisterTrustedPresentationListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
+    field @FlaggedApi("com.android.window.flags.cover_display_opt_in") public static final int COMPAT_SMALL_COVER_SCREEN_OPT_IN = 1; // 0x1
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
     field @FlaggedApi("com.android.window.flags.untrusted_embedding_state_sharing") public static final String PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING = "android.window.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING";
@@ -54439,6 +54470,7 @@
     field public static final String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
     field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
     field public static final String PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS = "android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS";
+    field @FlaggedApi("com.android.window.flags.cover_display_opt_in") public static final String PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN = "android.window.PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN";
     field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE";
     field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE";
     field public static final String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS";
@@ -60872,6 +60904,7 @@
     method public float getShadowDx();
     method public float getShadowDy();
     method public float getShadowRadius();
+    method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public boolean getShiftDrawingOffsetForStartOverhang();
     method public final boolean getShowSoftInputOnFocus();
     method public CharSequence getText();
     method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier();
@@ -61008,6 +61041,7 @@
     method public void setSearchResultHighlights(@Nullable int...);
     method public void setSelectAllOnFocus(boolean);
     method public void setShadowLayer(float, float, float, int);
+    method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public void setShiftDrawingOffsetForStartOverhang(boolean);
     method public final void setShowSoftInputOnFocus(boolean);
     method public void setSingleLine();
     method public void setSingleLine(boolean);
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index 9b8ab9b..1b0da05 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -1461,6 +1461,7 @@
     New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getItalicOverride(int)
 UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int):
     New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int)
+
 UnflaggedApi: android.hardware.camera2.ExtensionCaptureRequest:
     New API must be flagged with @FlaggedApi: class android.hardware.camera2.ExtensionCaptureRequest
 UnflaggedApi: android.hardware.camera2.ExtensionCaptureRequest#ExtensionCaptureRequest():
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 20a621ba..15de42a 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -195,6 +195,8 @@
     field public static final String MANAGE_DEFAULT_APPLICATIONS = "android.permission.MANAGE_DEFAULT_APPLICATIONS";
     field public static final String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final String MANAGE_DEVICE_POLICY_APP_EXEMPTIONS = "android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS";
+    field @FlaggedApi("android.app.admin.flags.security_log_v2_enabled") public static final String MANAGE_DEVICE_POLICY_AUDIT_LOGGING = "android.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING";
+    field @FlaggedApi("android.app.admin.flags.device_theft_api_enabled") public static final String MANAGE_DEVICE_POLICY_THEFT_DETECTION = "android.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION";
     field @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") public static final String MANAGE_ENHANCED_CONFIRMATION_STATES = "android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES";
     field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS";
     field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
@@ -203,7 +205,6 @@
     field public static final String MANAGE_HOTWORD_DETECTION = "android.permission.MANAGE_HOTWORD_DETECTION";
     field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
     field public static final String MANAGE_LOW_POWER_STANDBY = "android.permission.MANAGE_LOW_POWER_STANDBY";
-    field @FlaggedApi("com.android.media.flags.limit_manage_media_projection") public static final String MANAGE_MEDIA_PROJECTION = "android.permission.MANAGE_MEDIA_PROJECTION";
     field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
     field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
     field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
@@ -594,6 +595,7 @@
     field public static final int FOREGROUND_SERVICE_API_TYPE_MICROPHONE = 6; // 0x6
     field public static final int FOREGROUND_SERVICE_API_TYPE_PHONE_CALL = 7; // 0x7
     field public static final int FOREGROUND_SERVICE_API_TYPE_USB = 8; // 0x8
+    field @FlaggedApi("android.media.audio.foreground_audio_control") public static final int PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL = 64; // 0x40
     field public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 2; // 0x2
     field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1
     field public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 4; // 0x4
@@ -624,6 +626,8 @@
     method public static String[] getOpStrs();
     method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
     method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[]);
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[], @NonNull String);
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermissionGroupUsage> getPermissionGroupUsageForPrivacyIndicator(boolean);
     method public static int opToDefaultMode(@NonNull String);
     method @Nullable public static String opToPermission(@NonNull String);
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(@NonNull String, int, @Nullable String, int);
@@ -1288,6 +1292,10 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DevicePolicyDrawableResource> CREATOR;
   }
 
+  public final class DevicePolicyIdentifiers {
+    field @FlaggedApi("android.app.admin.flags.security_log_v2_enabled") public static final String AUDIT_LOGGING_POLICY = "auditLogging";
+  }
+
   public class DevicePolicyKeyguardService extends android.app.Service {
     ctor public DevicePolicyKeyguardService();
     method @Nullable public void dismiss();
@@ -1316,12 +1324,14 @@
     method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public int getUserProvisioningState();
+    method @FlaggedApi("android.app.admin.flags.security_log_v2_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public boolean isAuditLogEnabled();
     method public boolean isDeviceManaged();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean isDpcDownloaded();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isManagedKiosk();
     method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
+    method @FlaggedApi("android.app.admin.flags.device_theft_api_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION) public boolean isTheftDetectionTriggered();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isUnattendedManagedKiosk();
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
@@ -1330,6 +1340,8 @@
     method @RequiresPermission(android.Manifest.permission.TRIGGER_LOST_MODE) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS) public void setApplicationExemptions(@NonNull String, @NonNull java.util.Set<java.lang.Integer>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @FlaggedApi("android.app.admin.flags.security_log_v2_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void setAuditLogEnabled(boolean);
+    method @FlaggedApi("android.app.admin.flags.security_log_v2_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void setAuditLogEventCallback(@NonNull java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.util.List<android.app.admin.SecurityLog.SecurityEvent>>);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
     method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setMaxPolicyStorageLimit(int);
@@ -4756,9 +4768,13 @@
 
   @FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class CameraOutputSurface {
     ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public CameraOutputSurface(@NonNull android.view.Surface, @NonNull android.util.Size);
+    method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public int getColorSpace();
+    method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public long getDynamicRangeProfile();
     method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int getImageFormat();
     method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.util.Size getSize();
     method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.view.Surface getSurface();
+    method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(int);
+    method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setDynamicRangeProfile(long);
   }
 
   @FlaggedApi("com.android.internal.camera.flags.concert_mode") public class CharacteristicsMap {
@@ -10239,6 +10255,7 @@
     ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String);
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilterToAutoTransact(@NonNull String);
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean defaultToObserveMode();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
@@ -10268,6 +10285,7 @@
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setCategoryOtherServiceEnabled(boolean);
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public void setDefaultToObserveMode(boolean);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -11333,6 +11351,7 @@
     method public long getLastAccessTimeMillis();
     method @NonNull public String getPackageName();
     method @NonNull public String getPermissionGroupName();
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") @NonNull public String getPersistentDeviceId();
     method @Nullable public CharSequence getProxyLabel();
     method public int getUid();
     method public boolean isActive();
@@ -14351,9 +14370,9 @@
 
   @FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") public abstract class DomainSelectionService extends android.app.Service {
     ctor public DomainSelectionService();
+    method @NonNull public java.util.concurrent.Executor getCreateExecutor();
     method public void onBarringInfoUpdated(int, int, @NonNull android.telephony.BarringInfo);
     method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
-    method @NonNull public java.util.concurrent.Executor onCreateExecutor();
     method public abstract void onDomainSelection(@NonNull android.telephony.DomainSelectionService.SelectionAttributes, @NonNull android.telephony.TransportSelectorCallback);
     method public void onServiceStateUpdated(int, int, @NonNull android.telephony.ServiceState);
     field public static final int SCAN_TYPE_FULL_SERVICE = 2; // 0x2
@@ -15133,6 +15152,7 @@
     method @Deprecated public boolean getDataEnabled(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getDefaultRespondViaMessageApplication();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion(int);
+    method @FlaggedApi("android.permission.flags.get_emergency_role_holder_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getEmergencyAssistancePackage();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index a6505c8..ca9fab8 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -535,6 +535,10 @@
     Listeners should always be at end of argument list (method `stopSatelliteTransmissionUpdates`)
 
 
+MethodNameUnits: android.hardware.camera2.extension.CameraOutputSurface#getColorSpace():
+    Expected method name units to be `Bytes`, was `Space` in `getColorSpace`
+
+
 MissingGetterMatchingBuilder: android.service.voice.HotwordTrainingData.Builder#addTrainingAudio(android.service.voice.HotwordTrainingAudio):
     android.service.voice.HotwordTrainingData does not declare a `getTrainingAudios()` method matching method android.service.voice.HotwordTrainingData.Builder.addTrainingAudio(android.service.voice.HotwordTrainingAudio)
 MissingGetterMatchingBuilder: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallViaAudioProcessing(boolean):
diff --git a/core/java/android/adaptiveauth/flags.aconfig b/core/java/android/adaptiveauth/flags.aconfig
index 39e46bb..de4e607 100644
--- a/core/java/android/adaptiveauth/flags.aconfig
+++ b/core/java/android/adaptiveauth/flags.aconfig
@@ -1,6 +1,13 @@
 package: "android.adaptiveauth"
 
 flag {
+  name: "enable_adaptive_auth"
+  namespace: "biometrics"
+  description: "Feature flag for enabling the new adaptive auth service"
+  bug: "285053096"
+}
+
+flag {
   name: "report_biometric_auth_attempts"
   namespace: "biometrics"
   description: "Control the usage of the biometric auth signal in adaptive auth"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a8d183a..237d31c 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.windowingModeToString;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.media.audio.Flags.FLAG_FOREGROUND_AUDIO_CONTROL;
 
 import android.Manifest;
 import android.annotation.ColorInt;
@@ -794,6 +795,7 @@
             PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK,
             PROCESS_CAPABILITY_BFSL,
             PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK,
+            PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProcessCapability {}
@@ -943,6 +945,14 @@
     public static final int PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK = 1 << 5;
 
     /**
+     * @hide
+     * Process can access volume APIs and can request audio focus with GAIN.
+     */
+    @FlaggedApi(FLAG_FOREGROUND_AUDIO_CONTROL)
+    @SystemApi
+    public static final int PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL = 1 << 6;
+
+    /**
      * @hide all capabilities, the ORing of all flags in {@link ProcessCapability}.
      *
      * Don't expose it as TestApi -- we may add new capabilities any time, which could
@@ -953,7 +963,8 @@
             | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
             | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
             | PROCESS_CAPABILITY_BFSL
-            | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+            | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK
+            | PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
 
     /**
      * All implicit capabilities. There are capabilities that process automatically have.
@@ -975,6 +986,7 @@
         pw.print((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-');
         pw.print((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
         pw.print((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-');
+        pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0 ? 'A' : '-');
     }
 
     /** @hide */
@@ -986,6 +998,7 @@
         sb.append((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-');
         sb.append((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
         sb.append((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-');
+        sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0 ? 'A' : '-');
     }
 
     /**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index e14bf68..2a2c5f0 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -20,6 +20,7 @@
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
 import static android.view.Display.INVALID_DISPLAY;
@@ -1849,7 +1850,7 @@
     public int getPendingIntentLaunchFlags() {
         // b/243794108: Ignore all flags except the new task flag, to be reconsidered in b/254490217
         return mPendingIntentLaunchFlags &
-                (FLAG_ACTIVITY_NEW_TASK | FLAG_RECEIVER_FOREGROUND);
+                (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_RECEIVER_FOREGROUND);
     }
 
     /**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 2100425..16c7753 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,7 +16,9 @@
 
 package android.app;
 
+
 import static android.location.flags.Flags.FLAG_LOCATION_BYPASS;
+import static android.media.audio.Flags.foregroundAudioControl;
 import static android.permission.flags.Flags.FLAG_OP_ENABLE_MOBILE_DATA_BY_USER;
 import static android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED;
 import static android.view.contentprotection.flags.Flags.FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED;
@@ -70,6 +72,8 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.permission.PermissionGroupUsage;
+import android.permission.PermissionUsageHelper;
 import android.provider.DeviceConfig;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -224,6 +228,7 @@
     private static Boolean sFullLog = null;
 
     final Context mContext;
+    private PermissionUsageHelper mUsageHelper;
 
     @UnsupportedAppUsage
     final IAppOpsService mService;
@@ -3229,6 +3234,10 @@
      * @hide
      */
     public static @Mode int opToDefaultMode(int op) {
+        if (op == OP_TAKE_AUDIO_FOCUS && foregroundAudioControl()) {
+            // when removing the flag, change the entry in sAppOpInfos for OP_TAKE_AUDIO_FOCUS
+            return AppOpsManager.MODE_FOREGROUND;
+        }
         return sAppOpInfos[op].defaultMode;
     }
 
@@ -7759,6 +7768,44 @@
     }
 
     /**
+     * Retrieve current operation state for all applications for a device.
+     *
+     * The mode of the ops returned are set for the package but may not reflect their effective
+     * state due to UID policy or because it's controlled by a different global op.
+     *
+     * Use {@link #unsafeCheckOp(String, int, String)}} or
+     * {@link #noteOp(String, int, String, String, String)} if the effective mode is needed.
+     *
+     * @param ops The set of operations you are interested in, or null if you want all of them.
+     * @param persistentDeviceId The device that the ops are attributed to.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+    @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+    public @NonNull List<AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[] ops,
+            @NonNull String persistentDeviceId) {
+        final int[] opCodes;
+        if (ops != null) {
+            final int opCount = ops.length;
+            opCodes = new int[opCount];
+            for (int i = 0; i < opCount; i++) {
+                opCodes[i] = sOpStrToOp.get(ops[i]);
+            }
+        } else {
+            opCodes = null;
+        }
+        final List<AppOpsManager.PackageOps> result;
+        try {
+            result =  mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return (result != null) ? result : Collections.emptyList();
+    }
+
+    /**
      * Retrieve current operation state for all applications.
      *
      * The mode of the ops returned are set for the package but may not reflect their effective
@@ -7774,7 +7821,8 @@
     @UnsupportedAppUsage
     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
         try {
-            return mService.getPackagesForOps(ops);
+            return mService.getPackagesForOpsForDevice(ops,
+                    VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -9940,6 +9988,30 @@
         appOpsNotedForAttribution.set(op);
     }
 
+    /**
+     * Get recent op usage data for CAMERA, MICROPHONE and LOCATION from all connected devices
+     * to power privacy indicator.
+     *
+     * @param includeMicrophoneUsage whether to retrieve microphone usage
+     * @return A list of permission groups currently or recently used by all apps by all users in
+     * the current profile group.
+     *
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+    @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS)
+    public List<PermissionGroupUsage> getPermissionGroupUsageForPrivacyIndicator(
+            boolean includeMicrophoneUsage) {
+        // Lazily initialize the usage helper
+        if (mUsageHelper == null) {
+            mUsageHelper = new PermissionUsageHelper(mContext);
+        }
+
+        return mUsageHelper.getOpUsageDataForAllDevices(includeMicrophoneUsage);
+    }
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index f727ee5..1b5b0fc 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -65,6 +67,8 @@
     private @Nullable BundleMerger mDeliveryGroupExtrasMerger;
     private @Nullable IntentFilter mDeliveryGroupMatchingFilter;
     private @DeferralPolicy int mDeferralPolicy;
+    private @CurrentTimeMillisLong long mEventTriggerTimestampMillis;
+    private @CurrentTimeMillisLong long mRemoteEventTriggerTimestampMillis;
 
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
@@ -190,6 +194,18 @@
             "android:broadcast.idForResponseEvent";
 
     /**
+     * Corresponds to {@link #setEventTriggerTimestampMillis(long)}.
+     */
+    private static final String KEY_EVENT_TRIGGER_TIMESTAMP =
+            "android:broadcast.eventTriggerTimestamp";
+
+    /**
+     * Corresponds to {@link #setRemoteEventTriggerTimestampMillis(long)}.
+     */
+    private static final String KEY_REMOTE_EVENT_TRIGGER_TIMESTAMP =
+            "android:broadcast.remoteEventTriggerTimestamp";
+
+    /**
      * Corresponds to {@link #setDeliveryGroupPolicy(int)}.
      */
     private static final String KEY_DELIVERY_GROUP_POLICY =
@@ -341,6 +357,8 @@
         mRequireNoneOfPermissions = opts.getStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS);
         mRequireCompatChangeId = opts.getLong(KEY_REQUIRE_COMPAT_CHANGE_ID, CHANGE_INVALID);
         mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT);
+        mEventTriggerTimestampMillis = opts.getLong(KEY_EVENT_TRIGGER_TIMESTAMP);
+        mRemoteEventTriggerTimestampMillis = opts.getLong(KEY_REMOTE_EVENT_TRIGGER_TIMESTAMP);
         mDeliveryGroupPolicy = opts.getInt(KEY_DELIVERY_GROUP_POLICY,
                 DELIVERY_GROUP_POLICY_ALL);
         mDeliveryGroupMatchingNamespaceFragment = opts.getString(KEY_DELIVERY_GROUP_NAMESPACE);
@@ -787,6 +805,60 @@
     }
 
     /**
+     * Set the timestamp for the event that triggered this broadcast, in
+     * {@link System#currentTimeMillis()} timebase.
+     *
+     * <p> For instance, if this broadcast is for a push message, then this timestamp
+     * could correspond to when the device received the message.
+     *
+     * @param timestampMillis the timestamp in {@link System#currentTimeMillis()} timebase that
+     *                        correspond to the event that triggered this broadcast.
+     */
+    @FlaggedApi(android.app.Flags.FLAG_BCAST_EVENT_TIMESTAMPS)
+    public void setEventTriggerTimestampMillis(@CurrentTimeMillisLong long timestampMillis) {
+        mEventTriggerTimestampMillis = timestampMillis;
+    }
+
+    /**
+     * Return the timestamp for the event that triggered this broadcast, in
+     * {@link System#currentTimeMillis()} timebase.
+     *
+     * @return the timestamp in {@link System#currentTimeMillis()} timebase that was previously
+     *         set using {@link #setEventTriggerTimestampMillis(long)}.
+     */
+    @FlaggedApi(android.app.Flags.FLAG_BCAST_EVENT_TIMESTAMPS)
+    public @CurrentTimeMillisLong long getEventTriggerTimestampMillis() {
+        return mEventTriggerTimestampMillis;
+    }
+
+    /**
+     * Set the timestamp for the remote event, if any, that triggered this broadcast, in
+     * {@link System#currentTimeMillis()} timebase.
+     *
+     * <p> For instance, if this broadcast is for a push message, then this timestamp
+     * could correspond to when the message originated remotely.
+     *
+     * @param timestampMillis the timestamp in {@link System#currentTimeMillis()} timebase that
+     *                        correspond to the remote event that triggered this broadcast.
+     */
+    @FlaggedApi(android.app.Flags.FLAG_BCAST_EVENT_TIMESTAMPS)
+    public void setRemoteEventTriggerTimestampMillis(@CurrentTimeMillisLong long timestampMillis) {
+        mRemoteEventTriggerTimestampMillis = timestampMillis;
+    }
+
+    /**
+     * Return the timestamp for the remote event that triggered this broadcast, in
+     * {@link System#currentTimeMillis()} timebase.
+     *
+     * @return the timestamp in {@link System#currentTimeMillis()} timebase that was previously
+     *         set using {@link #setRemoteEventTriggerTimestampMillis(long)}}.
+     */
+    @FlaggedApi(android.app.Flags.FLAG_BCAST_EVENT_TIMESTAMPS)
+    public @CurrentTimeMillisLong long getRemoteEventTriggerTimestampMillis() {
+        return mRemoteEventTriggerTimestampMillis;
+    }
+
+    /**
      * Sets deferral policy for this broadcast that specifies how this broadcast
      * can be deferred for delivery at some future point.
      */
@@ -1120,6 +1192,12 @@
         if (mIdForResponseEvent != 0) {
             b.putLong(KEY_ID_FOR_RESPONSE_EVENT, mIdForResponseEvent);
         }
+        if (mEventTriggerTimestampMillis > 0) {
+            b.putLong(KEY_EVENT_TRIGGER_TIMESTAMP, mEventTriggerTimestampMillis);
+        }
+        if (mRemoteEventTriggerTimestampMillis > 0) {
+            b.putLong(KEY_REMOTE_EVENT_TRIGGER_TIMESTAMP, mRemoteEventTriggerTimestampMillis);
+        }
         if (mDeliveryGroupPolicy != DELIVERY_GROUP_POLICY_ALL) {
             b.putInt(KEY_DELIVERY_GROUP_POLICY, mDeliveryGroupPolicy);
         }
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index f92ff83..da0cc01 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/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index ff23f09..350b1ed 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -34,3 +34,10 @@
      description: "Add a new callback in Service to indicate a FGS has reached its timeout."
      bug: "317799821"
 }
+
+flag {
+    name: "bcast_event_timestamps"
+    namespace: "backstage_power"
+    description: "Add APIs for clients to provide broadcast event trigger timestamps"
+    bug: "325136414"
+}
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
index a884ab0..3c56aaf 100644
--- a/core/java/android/app/admin/DevicePolicyIdentifiers.java
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -20,6 +20,7 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.admin.flags.Flags;
 import android.os.UserManager;
@@ -53,6 +54,15 @@
     public static final String SECURITY_LOGGING_POLICY = "securityLogging";
 
     /**
+     * String identifier for {@link DevicePolicyManager#setAuditLogEnabled}.
+     *
+     * @hide
+     */
+    @FlaggedApi(FLAG_SECURITY_LOG_V2_ENABLED)
+    @SystemApi
+    public static final String AUDIT_LOGGING_POLICY = "auditLogging";
+
+    /**
      * String identifier for {@link DevicePolicyManager#setLockTaskPackages}.
      */
     public static final String LOCK_TASK_POLICY = "lockTask";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 34fb754..a6fda9d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -45,6 +45,7 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_STATUS_BAR;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA;
@@ -54,7 +55,9 @@
 import static android.Manifest.permission.SET_TIME_ZONE;
 import static android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED;
 import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
+import static android.app.admin.flags.Flags.FLAG_SECURITY_LOG_V2_ENABLED;
 import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
+import static android.app.admin.flags.Flags.FLAG_IS_MTE_POLICY_ENFORCED;
 import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
 import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
@@ -153,6 +156,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.org.conscrypt.TrustedCertificateStore;
+import com.android.internal.os.Zygote;
 
 import java.io.ByteArrayInputStream;
 import java.io.FileNotFoundException;
@@ -230,7 +234,6 @@
     private final boolean mParentInstance;
     private final DevicePolicyResourcesManager mResourcesManager;
 
-
     /** @hide */
     public DevicePolicyManager(Context context, IDevicePolicyManager service) {
         this(context, service, false);
@@ -4117,6 +4120,19 @@
         return MTE_NOT_CONTROLLED_BY_POLICY;
     }
 
+    /**
+     * Get the current MTE state of the device.
+     *
+     * <a href="https://source.android.com/docs/security/test/memory-safety/arm-mte">
+     * Learn more about MTE</a>
+     *
+     * @return whether MTE is currently enabled on the device.
+     */
+    @FlaggedApi(FLAG_IS_MTE_POLICY_ENFORCED)
+    public static boolean isMtePolicyEnforced() {
+        return Zygote.nativeSupportsMemoryTagging();
+    }
+
     /** Indicates that content protection is not controlled by policy, allowing user to choose. */
     @FlaggedApi(android.view.contentprotection.flags.Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED)
     public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0;
@@ -14043,6 +14059,74 @@
     }
 
     /**
+     * Controls whether audit logging is enabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURITY_LOG_V2_ENABLED)
+    @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+    public void setAuditLogEnabled(boolean enabled) {
+        throwIfParentInstance("setAuditLogEnabled");
+        try {
+            mService.setAuditLogEnabled(mContext.getPackageName(), true);
+        } catch (RemoteException re) {
+            re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @return Whether audit logging is enabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURITY_LOG_V2_ENABLED)
+    @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+    public boolean isAuditLogEnabled() {
+        throwIfParentInstance("isAuditLogEnabled");
+        try {
+            return mService.isAuditLogEnabled(mContext.getPackageName());
+        } catch (RemoteException re) {
+            re.rethrowFromSystemServer();
+            // unreachable
+            return false;
+        }
+    }
+
+    /**
+     * Sets audit log event callback. Only one callback per UID is active at any time, when a new
+     * callback is set, the previous one is forgotten. Should only be called when audit log policy
+     * is enforced by the caller. Disabling the policy clears the callback. Each time a new callback
+     * is set, it will first be invoked with all the audit log events available at the time.
+     *
+     * @param callback callback to invoke when new audit log events become available or {@code null}
+     *                 to clear the callback.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURITY_LOG_V2_ENABLED)
+    @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+    public void setAuditLogEventCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @Nullable Consumer<List<SecurityEvent>> callback) {
+        throwIfParentInstance("setAuditLogEventCallback");
+        final IAuditLogEventsCallback wrappedCallback = callback == null
+                ? null
+                : new IAuditLogEventsCallback.Stub() {
+                    @Override
+                    public void onNewAuditLogEvents(List<SecurityEvent> events) {
+                        executor.execute(() -> callback.accept(events));
+                    }
+                };
+        try {
+            mService.setAuditLogEventsCallback(mContext.getPackageName(), wrappedCallback);
+        } catch (RemoteException re) {
+            re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called by device owner or profile owner of an organization-owned managed profile to retrieve
      * all new security logging entries since the last call to this API after device boots.
      *
@@ -17044,6 +17128,26 @@
     }
 
     /**
+     *
+     * Returns whether the device considers itself to be potentially stolen.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(value = MANAGE_DEVICE_POLICY_THEFT_DETECTION)
+    @FlaggedApi(Flags.FLAG_DEVICE_THEFT_API_ENABLED)
+    public boolean isTheftDetectionTriggered() {
+        throwIfParentInstance("isTheftDetectionTriggered");
+        if (mService == null) {
+            return false;
+        }
+        try {
+            return mService.isTheftDetectionTriggered(mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns a {@link DevicePolicyResourcesManager} containing the required APIs to set, reset,
      * and get device policy related resources.
      */
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 07ee8de..1aee9fe 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -338,4 +338,9 @@
      * Enforces resolved security logging policy, should only be invoked from device policy engine.
      */
     public abstract void enforceSecurityLoggingPolicy(boolean enabled);
+
+    /**
+     * Enforces resolved audit logging policy, should only be invoked from device policy engine.
+     */
+    public abstract void enforceAuditLoggingPolicy(boolean enabled);
 }
diff --git a/location/java/android/location/IGeocodeListener.aidl b/core/java/android/app/admin/IAuditLogEventsCallback.aidl
similarity index 66%
copy from location/java/android/location/IGeocodeListener.aidl
copy to core/java/android/app/admin/IAuditLogEventsCallback.aidl
index 8e10411..ab87117 100644
--- a/location/java/android/location/IGeocodeListener.aidl
+++ b/core/java/android/app/admin/IAuditLogEventsCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -14,16 +14,11 @@
  * limitations under the License.
  */
 
-package android.location;
+package android.app.admin;
 
-import android.location.Address;
+import android.app.admin.SecurityLog;
 
-/**
- * An interface for returning geocode results.
- *
- * {@hide}
- */
-interface IGeocodeListener {
-
-    oneway void onResults(String error, in List<Address> results);
-}
+/** @hide */
+oneway interface IAuditLogEventsCallback {
+    void onNewAuditLogEvents(in List<SecurityLog.SecurityEvent> events);
+}
\ No newline at end of file
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index f2466ac..3a7a891c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -32,6 +32,7 @@
 import android.app.admin.PackagePolicy;
 import android.app.admin.PasswordMetrics;
 import android.app.admin.FactoryResetProtectionPolicy;
+import android.app.admin.IAuditLogEventsCallback;
 import android.app.admin.ManagedProfileProvisioningParams;
 import android.app.admin.FullyManagedDeviceProvisioningParams;
 import android.app.admin.ManagedSubscriptionsPolicy;
@@ -441,6 +442,10 @@
     long forceNetworkLogs();
     long forceSecurityLogs();
 
+    void setAuditLogEnabled(String callerPackage, boolean enabled);
+    boolean isAuditLogEnabled(String callerPackage);
+    void setAuditLogEventsCallback(String callerPackage, in IAuditLogEventsCallback callback);
+
     boolean isUninstallInQueue(String packageName);
     void uninstallPackageWithActiveAdmins(String packageName);
 
@@ -576,6 +581,8 @@
     void setWifiSsidPolicy(String callerPackageName, in WifiSsidPolicy policy);
     WifiSsidPolicy getWifiSsidPolicy(String callerPackageName);
 
+    boolean isTheftDetectionTriggered(String callerPackageName);
+
     List<UserHandle> listForegroundAffiliatedUsers();
     void setDrawables(in List<DevicePolicyDrawableResource> drawables);
     void resetDrawables(in List<String> drawableIds);
diff --git a/location/java/android/location/GeocoderParams.aidl b/core/java/android/app/admin/SecurityLog.aidl
similarity index 73%
copy from location/java/android/location/GeocoderParams.aidl
copy to core/java/android/app/admin/SecurityLog.aidl
index 2484e20..e5ae2df 100644
--- a/location/java/android/location/GeocoderParams.aidl
+++ b/core/java/android/app/admin/SecurityLog.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2010, The Android Open Source Project
+ * 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
+ *      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,
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.location;
+package android.app.admin;
 
-parcelable GeocoderParams;
+/** @hide */
+parcelable SecurityLog.SecurityEvent;
\ No newline at end of file
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 726ddad..cbd8e5b 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -139,3 +139,10 @@
   description: "Add Headless DO support."
   bug: "289515470"
 }
+
+flag {
+  name: "is_mte_policy_enforced"
+  namespace: "enterprise"
+  description: "Allow to query whether MTE is enabled or not to check for compliance for enterprise policy"
+  bug: "322777918"
+}
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/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a8dba51..cae4fab 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1565,6 +1565,14 @@
     private Boolean requestRawExternalStorageAccess;
 
     /**
+     * If {@code false}, this app does not allow its activities to be replaced by another app.
+     * Is set from application manifest application tag's allowCrossUidActivitySwitchFromBelow
+     * attribute.
+     * @hide
+     */
+    public boolean allowCrossUidActivitySwitchFromBelow = true;
+
+    /**
      * Represents the default policy. The actual policy used will depend on other properties of
      * the application, e.g. the target SDK version.
      * @hide
@@ -1760,6 +1768,9 @@
                         + Integer.toHexString(localeConfigRes));
             }
             pw.println(prefix + "enableOnBackInvokedCallback=" + isOnBackInvokedCallbackEnabled());
+            pw.println(prefix + "allowCrossUidActivitySwitchFromBelow="
+                    + allowCrossUidActivitySwitchFromBelow);
+
         }
         pw.println(prefix + "createTimestamp=" + createTimestamp);
         if (mKnownActivityEmbeddingCerts != null) {
@@ -1877,6 +1888,8 @@
                 proto.write(ApplicationInfoProto.Detail.NATIVE_HEAP_ZERO_INIT,
                         nativeHeapZeroInitialized);
             }
+            proto.write(ApplicationInfoProto.Detail.ALLOW_CROSS_UID_ACTIVITY_SWITCH_FROM_BELOW,
+                    allowCrossUidActivitySwitchFromBelow);
             proto.end(detailToken);
         }
         if (!ArrayUtils.isEmpty(mKnownActivityEmbeddingCerts)) {
@@ -2002,6 +2015,7 @@
         nativeHeapZeroInitialized = orig.nativeHeapZeroInitialized;
         requestRawExternalStorageAccess = orig.requestRawExternalStorageAccess;
         localeConfigRes = orig.localeConfigRes;
+        allowCrossUidActivitySwitchFromBelow = orig.allowCrossUidActivitySwitchFromBelow;
         createTimestamp = SystemClock.uptimeMillis();
     }
 
@@ -2106,6 +2120,8 @@
             }
         }
         dest.writeInt(localeConfigRes);
+        dest.writeInt(allowCrossUidActivitySwitchFromBelow ? 1 : 0);
+
         sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
     }
 
@@ -2204,6 +2220,8 @@
             }
         }
         localeConfigRes = source.readInt();
+        allowCrossUidActivitySwitchFromBelow = source.readInt() != 0;
+
         mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source);
         if (mKnownActivityEmbeddingCerts.isEmpty()) {
             mKnownActivityEmbeddingCerts = null;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 49c8a7c..2a67353 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2554,6 +2554,15 @@
     public static final int INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST = -130;
 
     /**
+     * Installation failed return code: if the system failed to install the package that
+     * {@link android.R.attr#multiArch} is true in its manifest because its packaged
+     * native code did not match all of the natively ABIs supported by the system.
+     *
+     * @hide
+     */
+    public static final int INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS = -131;
+
+    /**
      * App minimum aspect ratio set by the user which will override app-defined aspect ratio.
      *
      * @hide
@@ -10452,6 +10461,8 @@
             case INSTALL_FAILED_SESSION_INVALID: return "INSTALL_FAILED_SESSION_INVALID";
             case INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST:
                 return "INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST";
+            case INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS:
+                return "INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS";
             default: return Integer.toString(status);
         }
     }
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
index b4fe7fe..53f56bc 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
+++ b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
@@ -18,8 +18,11 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.graphics.ImageFormat;
+import android.hardware.camera2.params.ColorSpaceProfiles;
+import android.hardware.camera2.params.DynamicRangeProfiles;
 import android.hardware.camera2.utils.SurfaceUtils;
 import android.util.Size;
 import android.view.Surface;
@@ -65,6 +68,8 @@
         mOutputSurface.size = new android.hardware.camera2.extension.Size();
         mOutputSurface.size.width = size.getWidth();
         mOutputSurface.size.height = size.getHeight();
+        mOutputSurface.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+        mOutputSurface.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
     }
 
     /**
@@ -95,4 +100,48 @@
     public @ImageFormat.Format int getImageFormat() {
         return mOutputSurface.imageFormat;
     }
+
+    /**
+     * Return the dynamic range profile. The default
+     * dynamicRangeProfile is
+     * {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
+     * unless specified by CameraOutputSurface.setDynamicRangeProfile.
+     */
+    @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+    public @DynamicRangeProfiles.Profile long getDynamicRangeProfile() {
+        return mOutputSurface.dynamicRangeProfile;
+    }
+
+    /**
+     * Return the color space. The default colorSpace is
+     * {@link android.hardware.camera2.params.ColorSpaceProfiles.UNSPECIFIED}
+     * unless specified by CameraOutputSurface.setColorSpace.
+     */
+    @SuppressLint("MethodNameUnits")
+    @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+    public int getColorSpace() {
+        return mOutputSurface.colorSpace;
+    }
+
+    /**
+     * Set the dynamic range profile. The default dynamicRangeProfile
+     * will be {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
+     * unless explicitly set using this method.
+     */
+    @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+    public void setDynamicRangeProfile(
+            @DynamicRangeProfiles.Profile long dynamicRangeProfile) {
+        mOutputSurface.dynamicRangeProfile = dynamicRangeProfile;
+    }
+
+    /**
+     * Set the color space. The default colorSpace
+     * will be
+     * {@link android.hardware.camera2.params.ColorSpaceProfiles.UNSPECIFIED}
+     * unless explicitly set using this method.
+     */
+    @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+    public void setColorSpace(int colorSpace) {
+        mOutputSurface.colorSpace = colorSpace;
+    }
 }
diff --git a/core/java/android/hardware/camera2/extension/OutputSurface.aidl b/core/java/android/hardware/camera2/extension/OutputSurface.aidl
index 8415379..02e160c 100644
--- a/core/java/android/hardware/camera2/extension/OutputSurface.aidl
+++ b/core/java/android/hardware/camera2/extension/OutputSurface.aidl
@@ -24,4 +24,6 @@
     Surface surface;
     Size size;
     int imageFormat;
+    long dynamicRangeProfile;
+    int colorSpace;
 }
diff --git a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
index 0e6c1b3..69a6e9b 100644
--- a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
@@ -15,15 +15,20 @@
  */
 package android.hardware.camera2.params;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-
+import android.annotation.SuppressLint;
+import android.graphics.ColorSpace;
+import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraExtensionCharacteristics.Extension;
 import android.hardware.camera2.CameraExtensionSession;
 
 import java.util.List;
 import java.util.concurrent.Executor;
 
+import com.android.internal.camera.flags.Flags;
+
 /**
  * A class that aggregates all supported arguments for
  * {@link CameraExtensionSession} initialization.
@@ -36,6 +41,7 @@
     private OutputConfiguration mPostviewOutput = null;
     private Executor mExecutor = null;
     private CameraExtensionSession.StateCallback mCallback = null;
+    private int mColorSpace;
 
     /**
      * Create a new ExtensionSessionConfiguration
@@ -118,4 +124,55 @@
     Executor getExecutor() {
         return mExecutor;
     }
+
+    /**
+     * Set a specific device-supported color space.
+     *
+     * <p>Clients can choose from any profile advertised as supported in
+     * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}
+     * queried using {@link ColorSpaceProfiles#getSupportedColorSpaces}.
+     * When set, the colorSpace will override the default color spaces of the output targets,
+     * or the color space implied by the dataSpace passed into an {@link ImageReader}'s
+     * constructor.</p>
+     */
+    @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+    public void setColorSpace(@NonNull ColorSpace.Named colorSpace) {
+        mColorSpace = colorSpace.ordinal();
+        for (OutputConfiguration outputConfiguration : mOutputs) {
+            outputConfiguration.setColorSpace(colorSpace);
+        }
+        if (mPostviewOutput != null) {
+            mPostviewOutput.setColorSpace(colorSpace);
+        }
+    }
+
+    /**
+     * Clear the color space, such that the default color space will be used.
+     */
+    @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+    public void clearColorSpace() {
+        mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
+        for (OutputConfiguration outputConfiguration : mOutputs) {
+            outputConfiguration.clearColorSpace();
+        }
+        if (mPostviewOutput != null) {
+            mPostviewOutput.clearColorSpace();
+        }
+    }
+
+    /**
+     * Return the current color space.
+     *
+     * @return the currently set color space, or null
+     *         if not set
+     */
+    @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+    @SuppressLint("MethodNameUnits")
+    public @Nullable ColorSpace getColorSpace() {
+        if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
+            return ColorSpace.get(ColorSpace.Named.values()[mColorSpace]);
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/permission/PermissionGroupUsage.java b/core/java/android/permission/PermissionGroupUsage.java
index 49b7463..6895d3c 100644
--- a/core/java/android/permission/PermissionGroupUsage.java
+++ b/core/java/android/permission/PermissionGroupUsage.java
@@ -17,6 +17,7 @@
 package android.permission;
 
 import android.annotation.CurrentTimeMillisLong;
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -26,8 +27,8 @@
 
 /**
  * Represents the usage of a permission group by an app. Supports package name, user, permission
- * group, whether or not the access is running or recent, whether the access is tied to a phone
- * call, and an optional special attribution tag, label and proxy label.
+ * group, persistent device Id, whether or not the access is running or recent, whether the access
+ * is tied to a phone call, and an optional special attribution tag, label and proxy label.
  *
  * @hide
  */
@@ -48,6 +49,7 @@
     private final @Nullable CharSequence mAttributionTag;
     private final @Nullable CharSequence mAttributionLabel;
     private final @Nullable CharSequence mProxyLabel;
+    private final @NonNull String mPersistentDeviceId;
 
 
 
@@ -79,7 +81,8 @@
             boolean phoneCall,
             @Nullable CharSequence attributionTag,
             @Nullable CharSequence attributionLabel,
-            @Nullable CharSequence proxyLabel) {
+            @Nullable CharSequence proxyLabel,
+            @NonNull String persistentDeviceId) {
         this.mPackageName = packageName;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPackageName);
@@ -93,6 +96,9 @@
         this.mAttributionTag = attributionTag;
         this.mAttributionLabel = attributionLabel;
         this.mProxyLabel = proxyLabel;
+        this.mPersistentDeviceId = persistentDeviceId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mPersistentDeviceId);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -170,6 +176,12 @@
         return mProxyLabel;
     }
 
+    @DataClass.Generated.Member
+    @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+    public @NonNull String getPersistentDeviceId() {
+        return mPersistentDeviceId;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -185,7 +197,8 @@
                 "phoneCall = " + mPhoneCall + ", " +
                 "attributionTag = " + mAttributionTag + ", " +
                 "attributionLabel = " + mAttributionLabel + ", " +
-                "proxyLabel = " + mProxyLabel +
+                "proxyLabel = " + mProxyLabel + ", " +
+                "persistentDeviceId = " + mPersistentDeviceId +
         " }";
     }
 
@@ -210,7 +223,8 @@
                 && mPhoneCall == that.mPhoneCall
                 && java.util.Objects.equals(mAttributionTag, that.mAttributionTag)
                 && java.util.Objects.equals(mAttributionLabel, that.mAttributionLabel)
-                && java.util.Objects.equals(mProxyLabel, that.mProxyLabel);
+                && java.util.Objects.equals(mProxyLabel, that.mProxyLabel)
+                && java.util.Objects.equals(mPersistentDeviceId, that.mPersistentDeviceId);
     }
 
     @Override
@@ -229,6 +243,7 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
         _hash = 31 * _hash + java.util.Objects.hashCode(mAttributionLabel);
         _hash = 31 * _hash + java.util.Objects.hashCode(mProxyLabel);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mPersistentDeviceId);
         return _hash;
     }
 
@@ -252,6 +267,7 @@
         if (mAttributionTag != null) dest.writeCharSequence(mAttributionTag);
         if (mAttributionLabel != null) dest.writeCharSequence(mAttributionLabel);
         if (mProxyLabel != null) dest.writeCharSequence(mProxyLabel);
+        dest.writeString(mPersistentDeviceId);
     }
 
     @Override
@@ -275,6 +291,7 @@
         CharSequence attributionTag = (flg & 0x40) == 0 ? null : (CharSequence) in.readCharSequence();
         CharSequence attributionLabel = (flg & 0x80) == 0 ? null : (CharSequence) in.readCharSequence();
         CharSequence proxyLabel = (flg & 0x100) == 0 ? null : (CharSequence) in.readCharSequence();
+        String persistentDeviceId = in.readString();
 
         this.mPackageName = packageName;
         com.android.internal.util.AnnotationValidations.validate(
@@ -289,6 +306,9 @@
         this.mAttributionTag = attributionTag;
         this.mAttributionLabel = attributionLabel;
         this.mProxyLabel = proxyLabel;
+        this.mPersistentDeviceId = persistentDeviceId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mPersistentDeviceId);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -308,10 +328,10 @@
     };
 
     @DataClass.Generated(
-            time = 1645067417023L,
+            time = 1706285211875L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/permission/PermissionGroupUsage.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final  int mUid\nprivate final  long mLastAccessTimeMillis\nprivate final @android.annotation.NonNull java.lang.String mPermissionGroupName\nprivate final  boolean mActive\nprivate final  boolean mPhoneCall\nprivate final @android.annotation.Nullable java.lang.CharSequence mAttributionTag\nprivate final @android.annotation.Nullable java.lang.CharSequence mAttributionLabel\nprivate final @android.annotation.Nullable java.lang.CharSequence mProxyLabel\nclass PermissionGroupUsage extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true, genToString=true)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final  int mUid\nprivate final  long mLastAccessTimeMillis\nprivate final @android.annotation.NonNull java.lang.String mPermissionGroupName\nprivate final  boolean mActive\nprivate final  boolean mPhoneCall\nprivate final @android.annotation.Nullable java.lang.CharSequence mAttributionTag\nprivate final @android.annotation.Nullable java.lang.CharSequence mAttributionLabel\nprivate final @android.annotation.Nullable java.lang.CharSequence mProxyLabel\nprivate final @android.annotation.NonNull java.lang.String mPersistentDeviceId\nclass PermissionGroupUsage extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index e6b8102..fd52c76 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -1329,7 +1329,9 @@
     public List<PermissionGroupUsage> getIndicatorAppOpUsageData(boolean micMuted) {
         // Lazily initialize the usage helper
         initializeUsageHelper();
-        return mUsageHelper.getOpUsageData(micMuted);
+        boolean includeMicrophoneUsage = !micMuted;
+        return mUsageHelper.getOpUsageDataByDevice(includeMicrophoneUsage,
+                VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
     }
 
     /**
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 1f798ba..460b4dd 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -41,6 +41,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
+import android.companion.virtual.VirtualDevice;
+import android.companion.virtual.VirtualDeviceManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.Attribution;
@@ -52,10 +54,12 @@
 import android.media.AudioManager;
 import android.os.Process;
 import android.os.UserHandle;
+import android.permission.flags.Flags;
 import android.provider.DeviceConfig;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -75,6 +79,8 @@
 public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener,
         AppOpsManager.OnOpStartedListener {
 
+    private static final String LOG_TAG = PermissionUsageHelper.class.getName();
+
     /**
      * Whether to show the mic and camera icons.
      */
@@ -159,6 +165,7 @@
     private ArrayMap<UserHandle, Context> mUserContexts;
     private PackageManager mPkgManager;
     private AppOpsManager mAppOpsManager;
+    private VirtualDeviceManager mVirtualDeviceManager;
     @GuardedBy("mAttributionChains")
     private final ArrayMap<Integer, ArrayList<AccessChainLink>> mAttributionChains =
             new ArrayMap<>();
@@ -172,6 +179,7 @@
         mContext = context;
         mPkgManager = context.getPackageManager();
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
+        mVirtualDeviceManager = context.getSystemService(VirtualDeviceManager.class);
         mUserContexts = new ArrayMap<>();
         mUserContexts.put(Process.myUserHandle(), mContext);
         // TODO ntmyren: make this listen for flag enable/disable changes
@@ -280,9 +288,11 @@
     }
 
     /**
-     * @see PermissionManager.getIndicatorAppOpUsageData
+     * Return Op usage for CAMERA, LOCATION AND MICROPHONE for all packages for a device.
+     * The returned data is to power privacy indicator.
      */
-    public @NonNull List<PermissionGroupUsage> getOpUsageData(boolean isMicMuted) {
+    public @NonNull List<PermissionGroupUsage> getOpUsageDataByDevice(
+            boolean includeMicrophoneUsage, String deviceId) {
         List<PermissionGroupUsage> usages = new ArrayList<>();
 
         if (!shouldShowIndicators()) {
@@ -293,11 +303,11 @@
         if (shouldShowLocationIndicator()) {
             ops.addAll(LOCATION_OPS);
         }
-        if (!isMicMuted) {
+        if (includeMicrophoneUsage) {
             ops.addAll(MIC_OPS);
         }
 
-        Map<String, List<OpUsage>> rawUsages = getOpUsages(ops);
+        Map<String, List<OpUsage>> rawUsages = getOpUsagesByDevice(ops, deviceId);
 
         ArrayList<String> usedPermGroups = new ArrayList<>(rawUsages.keySet());
 
@@ -349,13 +359,40 @@
                         new PermissionGroupUsage(usage.packageName, usage.uid, usage.lastAccessTime,
                                 permGroup,
                                 usage.isRunning, isPhone, usage.attributionTag, attributionLabel,
-                                usagesWithLabels.valueAt(usageNum)));
+                                usagesWithLabels.valueAt(usageNum),
+                                VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT));
             }
         }
 
         return usages;
     }
 
+    /**
+     * Return Op usage for CAMERA, LOCATION AND MICROPHONE for all packages and all connected
+     * devices.
+     * The returned data is to power privacy indicator.
+     */
+    public @NonNull List<PermissionGroupUsage> getOpUsageDataForAllDevices(
+            boolean includeMicrophoneUsage) {
+        List<PermissionGroupUsage> allUsages = new ArrayList<>();
+        List<VirtualDevice> virtualDevices = mVirtualDeviceManager.getVirtualDevices();
+        ArraySet<String> persistentDeviceIds = new ArraySet<>();
+
+        for (int num = 0; num < virtualDevices.size(); num++) {
+            persistentDeviceIds.add(virtualDevices.get(num).getPersistentDeviceId());
+        }
+        persistentDeviceIds.add(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+
+        for (int index = 0; index < persistentDeviceIds.size(); index++) {
+            allUsages.addAll(
+                    getOpUsageDataByDevice(includeMicrophoneUsage,
+                            persistentDeviceIds.valueAt(index)));
+        }
+
+        return allUsages;
+    }
+
+
     private void updateSubattributionLabelsMap(List<OpUsage> usages,
             ArrayMap<String, Map<String, String>> subAttributionLabelsMap) {
         if (usages == null || usages.isEmpty()) {
@@ -443,12 +480,24 @@
      * running/recent info, if the usage is a phone call, per permission group.
      *
      * @param opNames a list of op names to get usage for
+     * @param deviceId which device to get op usage for
      * @return A map of permission group -> list of usages that are recent or running
      */
-    private Map<String, List<OpUsage>> getOpUsages(List<String> opNames) {
+    private Map<String, List<OpUsage>> getOpUsagesByDevice(List<String> opNames, String deviceId) {
         List<AppOpsManager.PackageOps> ops;
         try {
-            ops = mAppOpsManager.getPackagesForOps(opNames.toArray(new String[opNames.size()]));
+            if (Flags.deviceAwarePermissionApisEnabled()) {
+                ops = mAppOpsManager.getPackagesForOps(opNames.toArray(new String[opNames.size()]),
+                        deviceId);
+            } else if (!Objects.equals(deviceId,
+                    VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) {
+                Slog.w(LOG_TAG,
+                        "device_aware_permission_apis_enabled flag not enabled when deviceId is "
+                                + "not default");
+                return Collections.emptyMap();
+            } else {
+                ops = mAppOpsManager.getPackagesForOps(opNames.toArray(new String[opNames.size()]));
+            }
         } catch (NullPointerException e) {
             // older builds might not support all the app-ops requested
             return Collections.emptyMap();
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index e8c8b5a..9218cb8 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -111,3 +111,22 @@
     description: "When the flag is off no permissions can be device aware"
     bug: "274852670"
 }
+
+flag {
+     name: "get_emergency_role_holder_api_enabled"
+     is_fixed_read_only: true
+     namespace: "permissions"
+     description: "Enables the getEmergencyRoleHolder API."
+     bug: "323157319"
+}
+
+flag {
+    name: "new_permission_gid_enabled"
+    is_fixed_read_only: true
+    namespace: "permissions"
+    description: "Enable new permission GID implementation"
+    bug: "325137277"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
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/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 2028c40..9db8aa1 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -273,7 +273,7 @@
                 outerwidth /* ellipsizedWidth */, null /* ellipsize */, 1 /* maxLines */,
                 BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null /* leftIndents */,
                 null /* rightIndents */, JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false,
-                null);
+                false /* shiftDrawingOffsetForStartOverhang */, null);
 
         mEllipsizedWidth = outerwidth;
         mEllipsizedStart = 0;
@@ -346,7 +346,8 @@
                 ellipsizedWidth, ellipsize, 1 /* maxLines */,
                 BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null /* leftIndents */,
                 null /* rightIndents */, JUSTIFICATION_MODE_NONE,
-                LineBreakConfig.NONE, metrics, false /* useBoundsForWidth */, null);
+                LineBreakConfig.NONE, metrics, false /* useBoundsForWidth */,
+                false /* shiftDrawingOffsetForStartOverhang */, null);
     }
 
     /** @hide */
@@ -363,12 +364,14 @@
             TextUtils.TruncateAt ellipsize,
             Metrics metrics,
             boolean useBoundsForWidth,
+            boolean shiftDrawingOffsetForStartOverhang,
             @Nullable Paint.FontMetrics minimumFontMetrics) {
         this(text, paint, width, align, TextDirectionHeuristics.LTR,
                 spacingMult, spacingAdd, includePad, fallbackLineSpacing, ellipsizedWidth,
                 ellipsize, 1 /* maxLines */, Layout.BREAK_STRATEGY_SIMPLE,
                 Layout.HYPHENATION_FREQUENCY_NONE, null, null, Layout.JUSTIFICATION_MODE_NONE,
-                LineBreakConfig.NONE, metrics, useBoundsForWidth, minimumFontMetrics);
+                LineBreakConfig.NONE, metrics, useBoundsForWidth,
+                shiftDrawingOffsetForStartOverhang, minimumFontMetrics);
     }
 
     /* package */ BoringLayout(
@@ -392,12 +395,14 @@
             LineBreakConfig lineBreakConfig,
             Metrics metrics,
             boolean useBoundsForWidth,
+            boolean shiftDrawingOffsetForStartOverhang,
             @Nullable Paint.FontMetrics minimumFontMetrics) {
 
         super(text, paint, width, align, textDir, spacingMult, spacingAdd, includePad,
                 fallbackLineSpacing, ellipsizedWidth, ellipsize, maxLines, breakStrategy,
                 hyphenationFrequency, leftIndents, rightIndents, justificationMode,
-                lineBreakConfig, useBoundsForWidth, minimumFontMetrics);
+                lineBreakConfig, useBoundsForWidth, shiftDrawingOffsetForStartOverhang,
+                minimumFontMetrics);
 
 
         boolean trust;
@@ -712,7 +717,7 @@
                      int cursorOffset) {
         if (mDirect != null && highlight == null) {
             float leftShift = 0;
-            if (getUseBoundsForWidth()) {
+            if (getUseBoundsForWidth() && getShiftDrawingOffsetForStartOverhang()) {
                 RectF drawingRect = computeDrawingBoundingBox();
                 if (drawingRect.left < 0) {
                     leftShift = -drawingRect.left;
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 9286049..cce4f7b 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -25,6 +25,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Paint;
 import android.graphics.Rect;
@@ -317,6 +318,35 @@
         }
 
         /**
+         * Set true for shifting the drawing x offset for showing overhang at the start position.
+         *
+         * This flag is ignored if the {@link #getUseBoundsForWidth()} is false.
+         *
+         * If this value is false, the Layout draws text from the zero even if there is a glyph
+         * stroke in a region where the x coordinate is negative.
+         *
+         * If this value is true, the Layout draws text with shifting the x coordinate of the
+         * drawing bounding box.
+         *
+         * This value is false by default.
+         *
+         * @param shiftDrawingOffsetForStartOverhang true for shifting the drawing offset for
+         *                                          showing the stroke that is in the region where
+         *                                          the x coordinate is negative.
+         * @see #setUseBoundsForWidth(boolean)
+         * @see #getUseBoundsForWidth()
+         */
+        @NonNull
+        // The corresponding getter is getShiftDrawingOffsetForStartOverhang()
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+        public Builder setShiftDrawingOffsetForStartOverhang(
+                boolean shiftDrawingOffsetForStartOverhang) {
+            mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
+            return this;
+        }
+
+        /**
          * Set the minimum font metrics used for line spacing.
          *
          * <p>
@@ -386,6 +416,7 @@
         private int mEllipsizedWidth;
         private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
         private boolean mUseBoundsForWidth;
+        private boolean mShiftDrawingOffsetForStartOverhang;
         private @Nullable Paint.FontMetrics mMinimumFontMetrics;
 
         private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
@@ -462,7 +493,8 @@
                 false /* fallbackLineSpacing */, ellipsizedWidth, ellipsize,
                 Integer.MAX_VALUE /* maxLines */, breakStrategy, hyphenationFrequency,
                 null /* leftIndents */, null /* rightIndents */, justificationMode,
-                lineBreakConfig, false /* useBoundsForWidth */, null /* minimumFontMetrics */);
+                lineBreakConfig, false /* useBoundsForWidth */, false,
+                null /* minimumFontMetrics */);
 
         final Builder b = Builder.obtain(base, paint, width)
                 .setAlignment(align)
@@ -488,7 +520,8 @@
                 b.mIncludePad, b.mFallbackLineSpacing, b.mEllipsizedWidth, b.mEllipsize,
                 Integer.MAX_VALUE /* maxLines */, b.mBreakStrategy, b.mHyphenationFrequency,
                 null /* leftIndents */, null /* rightIndents */, b.mJustificationMode,
-                b.mLineBreakConfig, b.mUseBoundsForWidth, b.mMinimumFontMetrics);
+                b.mLineBreakConfig, b.mUseBoundsForWidth, b.mShiftDrawingOffsetForStartOverhang,
+                b.mMinimumFontMetrics);
 
         mDisplay = b.mDisplay;
         mIncludePad = b.mIncludePad;
@@ -516,6 +549,7 @@
         mBase = b.mBase;
         mFallbackLineSpacing = b.mFallbackLineSpacing;
         mUseBoundsForWidth = b.mUseBoundsForWidth;
+        mShiftDrawingOffsetForStartOverhang = b.mShiftDrawingOffsetForStartOverhang;
         mMinimumFontMetrics = b.mMinimumFontMetrics;
         if (b.mEllipsize != null) {
             mInts = new PackedIntVector(COLUMNS_ELLIPSIZE);
@@ -713,6 +747,7 @@
                 .setAddLastLineLineSpacing(!islast)
                 .setIncludePad(false)
                 .setUseBoundsForWidth(mUseBoundsForWidth)
+                .setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang)
                 .setMinimumFontMetrics(mMinimumFontMetrics)
                 .setCalculateBounds(true);
 
@@ -1392,6 +1427,7 @@
     private Rect mTempRect = new Rect();
 
     private boolean mUseBoundsForWidth;
+    private boolean mShiftDrawingOffsetForStartOverhang;
     @Nullable Paint.FontMetrics mMinimumFontMetrics;
 
     @UnsupportedAppUsage
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index e5d199a..8e52af3 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -44,6 +44,7 @@
 import android.text.style.ParagraphStyle;
 import android.text.style.ReplacementSpan;
 import android.text.style.TabStopSpan;
+import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -299,7 +300,7 @@
         this(text, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
                 spacingMult, spacingAdd, false, false, 0, null, Integer.MAX_VALUE,
                 BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null, null,
-                JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false, null);
+                JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false, false, null);
     }
 
     /**
@@ -349,6 +350,7 @@
             int justificationMode,
             LineBreakConfig lineBreakConfig,
             boolean useBoundsForWidth,
+            boolean shiftDrawingOffsetForStartOverhang,
             Paint.FontMetrics minimumFontMetrics
     ) {
 
@@ -384,6 +386,7 @@
         mJustificationMode = justificationMode;
         mLineBreakConfig = lineBreakConfig;
         mUseBoundsForWidth = useBoundsForWidth;
+        mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
         mMinimumFontMetrics = minimumFontMetrics;
     }
 
@@ -465,7 +468,7 @@
             @Nullable Paint selectionPaint,
             int cursorOffsetVertical) {
         float leftShift = 0;
-        if (mUseBoundsForWidth) {
+        if (mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
             RectF drawingRect = computeDrawingBoundingBox();
             if (drawingRect.left < 0) {
                 leftShift = -drawingRect.left;
@@ -3414,6 +3417,7 @@
     private int mJustificationMode;
     private LineBreakConfig mLineBreakConfig;
     private boolean mUseBoundsForWidth;
+    private boolean mShiftDrawingOffsetForStartOverhang;
     private @Nullable Paint.FontMetrics mMinimumFontMetrics;
 
     private TextLine.LineInfo mLineInfo = null;
@@ -3873,6 +3877,35 @@
         }
 
         /**
+         * Set true for shifting the drawing x offset for showing overhang at the start position.
+         *
+         * This flag is ignored if the {@link #getUseBoundsForWidth()} is false.
+         *
+         * If this value is false, the Layout draws text from the zero even if there is a glyph
+         * stroke in a region where the x coordinate is negative.
+         *
+         * If this value is true, the Layout draws text with shifting the x coordinate of the
+         * drawing bounding box.
+         *
+         * This value is false by default.
+         *
+         * @param shiftDrawingOffsetForStartOverhang true for shifting the drawing offset for
+         *                                          showing the stroke that is in the region where
+         *                                          the x coordinate is negative.
+         * @see #setUseBoundsForWidth(boolean)
+         * @see #getUseBoundsForWidth()
+         */
+        @NonNull
+        // The corresponding getter is getShiftDrawingOffsetForStartOverhang()
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+        public Builder setShiftDrawingOffsetForStartOverhang(
+                boolean shiftDrawingOffsetForStartOverhang) {
+            mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
+            return this;
+        }
+
+        /**
          * Set the minimum font metrics used for line spacing.
          *
          * <p>
@@ -3948,6 +3981,7 @@
                         .setJustificationMode(mJustificationMode)
                         .setLineBreakConfig(mLineBreakConfig)
                         .setUseBoundsForWidth(mUseBoundsForWidth)
+                        .setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang)
                         .build();
             } else {
                 return new BoringLayout(
@@ -3955,7 +3989,7 @@
                         mIncludePad, mFallbackLineSpacing, mEllipsizedWidth, mEllipsize, mMaxLines,
                         mBreakStrategy, mHyphenationFrequency, mLeftIndents, mRightIndents,
                         mJustificationMode, mLineBreakConfig, metrics, mUseBoundsForWidth,
-                        mMinimumFontMetrics);
+                        mShiftDrawingOffsetForStartOverhang, mMinimumFontMetrics);
             }
         }
 
@@ -3980,6 +4014,7 @@
         private int mJustificationMode = JUSTIFICATION_MODE_NONE;
         private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
         private boolean mUseBoundsForWidth;
+        private boolean mShiftDrawingOffsetForStartOverhang;
         private Paint.FontMetrics mMinimumFontMetrics;
     }
 
@@ -4294,6 +4329,20 @@
     }
 
     /**
+     * Returns true if shifting drawing offset for start overhang.
+     *
+     * @return True if shifting drawing offset for start overhang.
+     * @see android.widget.TextView#setShiftDrawingOffsetForStartOverhang(boolean)
+     * @see TextView#getShiftDrawingOffsetForStartOverhang()
+     * @see StaticLayout.Builder#setShiftDrawingOffsetForStartOverhang(boolean)
+     * @see DynamicLayout.Builder#setShiftDrawingOffsetForStartOverhang(boolean)
+     */
+    @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+    public boolean getShiftDrawingOffsetForStartOverhang() {
+        return mShiftDrawingOffsetForStartOverhang;
+    }
+
+    /**
      * Get the minimum font metrics used for line spacing.
      *
      * @see android.widget.TextView#setMinimumFontMetrics(Paint.FontMetrics)
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 5986238..3dd3a9e 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -24,6 +24,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Paint;
 import android.graphics.RectF;
@@ -454,6 +455,35 @@
         }
 
         /**
+         * Set true for shifting the drawing x offset for showing overhang at the start position.
+         *
+         * This flag is ignored if the {@link #getUseBoundsForWidth()} is false.
+         *
+         * If this value is false, the Layout draws text from the zero even if there is a glyph
+         * stroke in a region where the x coordinate is negative.
+         *
+         * If this value is true, the Layout draws text with shifting the x coordinate of the
+         * drawing bounding box.
+         *
+         * This value is false by default.
+         *
+         * @param shiftDrawingOffsetForStartOverhang true for shifting the drawing offset for
+         *                                          showing the stroke that is in the region where
+         *                                          the x coordinate is negative.
+         * @see #setUseBoundsForWidth(boolean)
+         * @see #getUseBoundsForWidth()
+         */
+        @NonNull
+        // The corresponding getter is getShiftDrawingOffsetForStartOverhang()
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+        public Builder setShiftDrawingOffsetForStartOverhang(
+                boolean shiftDrawingOffsetForStartOverhang) {
+            mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
+            return this;
+        }
+
+        /**
          * Internal API that tells underlying line breaker that calculating bounding boxes even if
          * the line break is performed with advances. This is useful for DynamicLayout internal
          * implementation because it uses bounding box as well as advances.
@@ -566,6 +596,7 @@
         private boolean mAddLastLineLineSpacing;
         private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
         private boolean mUseBoundsForWidth;
+        private boolean mShiftDrawingOffsetForStartOverhang;
         private boolean mCalculateBounds;
         @Nullable private Paint.FontMetrics mMinimumFontMetrics;
 
@@ -599,6 +630,7 @@
                 JUSTIFICATION_MODE_NONE,
                 null,  // lineBreakConfig,
                 false,  // useBoundsForWidth
+                false,  // shiftDrawingOffsetForStartOverhang
                 null  // minimumFontMetrics
         );
 
@@ -677,7 +709,7 @@
                 b.mIncludePad, b.mFallbackLineSpacing, b.mEllipsizedWidth, b.mEllipsize,
                 b.mMaxLines, b.mBreakStrategy, b.mHyphenationFrequency, b.mLeftIndents,
                 b.mRightIndents, b.mJustificationMode, b.mLineBreakConfig, b.mUseBoundsForWidth,
-                b.mMinimumFontMetrics);
+                b.mShiftDrawingOffsetForStartOverhang, b.mMinimumFontMetrics);
 
         mColumns = columnSize;
         if (b.mEllipsize != null) {
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index 9413f5c..5ec41591 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -202,38 +202,4 @@
         throw new UnsupportedOperationException("The getInputTransferToken needs to be "
                 + "implemented before making this call.");
     }
-
-    /**
-     * Transfer the currently in progress touch gesture from the host to the requested
-     * {@link SurfaceControlViewHost.SurfacePackage}. This requires that the
-     * SurfaceControlViewHost was created with the current host's inputToken.
-     * <p>
-     * When the touch is transferred, the window currently receiving touch gets an ACTION_CANCEL
-     * and does not receive any further input events for this gesture.
-     * <p>
-     * The transferred-to window receives an ACTION_DOWN event and then the remainder of the
-     * input events for this gesture. It does not receive any of the previous events of this gesture
-     * that the originating window received.
-     * <p>
-     * The "transferTouch" API only works for the current gesture. When a new gesture arrives,
-     * input dispatcher will do a new round of hit testing. So, if the "host" window is still the
-     * first thing that's being touched, then it will receive the new gesture again. It will
-     * again be up to the host to transfer this new gesture to the embedded.
-     * <p>
-     * Once the transferred-to window receives the gesture, it can choose to give up this gesture
-     * and send it to another window that it's linked to (it can't be an arbitrary window for
-     * security reasons) using the same transferTouch API. Only the window currently receiving
-     * touch is allowed to transfer the gesture.
-     *
-     * @param surfacePackage The SurfacePackage to transfer the gesture to.
-     * @return Whether the touch stream was transferred.
-     * @see SurfaceControlViewHost#transferTouchGestureToHost() for the reverse to transfer touch
-     * gesture from the embedded to the host.
-     */
-    @FlaggedApi(Flags.FLAG_TRANSFER_GESTURE_TO_EMBEDDED)
-    default boolean transferHostTouchGestureToEmbedded(
-            @NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) {
-        throw new UnsupportedOperationException(
-                "transferHostTouchGestureToEmbedded is unimplemented");
-    }
 }
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index eb28920..676b903 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -23,6 +23,9 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.text.TextUtils;
+import android.view.inputmethod.ConnectionlessHandwritingCallback;
+import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.Flags;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
@@ -225,15 +228,7 @@
                             }
                             startHandwriting(candidateView);
                         } else if (candidateView.getHandwritingDelegatorCallback() != null) {
-                            String delegatePackageName =
-                                    candidateView.getAllowedHandwritingDelegatePackageName();
-                            if (delegatePackageName == null) {
-                                delegatePackageName = candidateView.getContext().getOpPackageName();
-                            }
-                            mImm.prepareStylusHandwritingDelegation(
-                                    candidateView, delegatePackageName);
-                            candidateView.getHandwritingDelegatorCallback().run();
-                            mState.mHasPreparedHandwritingDelegation = true;
+                            prepareDelegation(candidateView);
                         } else {
                             if (!mInitiateWithoutConnection) {
                                 mState.mPendingConnectedView = new WeakReference<>(candidateView);
@@ -375,7 +370,7 @@
             // A new view just gain focus. By default, we should show hover icon for it.
             mShowHoverIconForConnectedView = true;
         }
-        if (!fromTouchEvent) {
+        if (!fromTouchEvent && view.isHandwritingDelegate()) {
             tryAcceptStylusHandwritingDelegation(view);
         }
         return true;
@@ -393,15 +388,33 @@
         }
     }
 
+    private void prepareDelegation(View view) {
+        String delegatePackageName = view.getAllowedHandwritingDelegatePackageName();
+        if (delegatePackageName == null) {
+            delegatePackageName = view.getContext().getOpPackageName();
+        }
+        if (mImm.isConnectionlessStylusHandwritingAvailable()) {
+            // No other view should have focus during the connectionless handwriting session, as
+            // this could cause user confusion about the input target for the session.
+            view.getViewRootImpl().getView().clearFocus();
+            mImm.startConnectionlessStylusHandwritingForDelegation(
+                    view, getCursorAnchorInfoForConnectionless(view), delegatePackageName,
+                    view::post, new DelegationCallback(view, delegatePackageName));
+            mState.mHasInitiatedHandwriting = true;
+            mState.mShouldInitHandwriting = false;
+        } else {
+            mImm.prepareStylusHandwritingDelegation(view, delegatePackageName);
+            view.getHandwritingDelegatorCallback().run();
+            mState.mHasPreparedHandwritingDelegation = true;
+        }
+    }
+
     /**
      * Starts a stylus handwriting session for the delegate view, if {@link
      * InputMethodManager#prepareStylusHandwritingDelegation} was previously called.
      */
     @VisibleForTesting
     public boolean tryAcceptStylusHandwritingDelegation(@NonNull View view) {
-        if (!view.isHandwritingDelegate() || (mState != null && mState.mHasInitiatedHandwriting)) {
-            return false;
-        }
         String delegatorPackageName =
                 view.getAllowedHandwritingDelegatorPackageName();
         if (delegatorPackageName == null) {
@@ -807,6 +820,59 @@
                 && view.shouldInitiateHandwriting();
     }
 
+    private CursorAnchorInfo getCursorAnchorInfoForConnectionless(View view) {
+        CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
+        // Fake editor views will usually display hint text. The hint text view can be used to
+        // populate the CursorAnchorInfo.
+        TextView textView = findFirstTextViewDescendent(view);
+        if (textView != null) {
+            textView.getCursorAnchorInfo(0, builder, mTempMatrix);
+            if (textView.getSelectionStart() < 0) {
+                // Insertion marker location is not populated if selection start is negative, so
+                // make a best guess.
+                float bottom = textView.getHeight() - textView.getExtendedPaddingBottom();
+                builder.setInsertionMarkerLocation(
+                        /* horizontalPosition= */ textView.getCompoundPaddingStart(),
+                        /* lineTop= */ textView.getExtendedPaddingTop(),
+                        /* lineBaseline= */ bottom,
+                        /* lineBottom= */ bottom,
+                        /* flags= */ 0);
+            }
+        } else {
+            // If there is no TextView descendent, just populate the insertion marker with the start
+            // edge of the view.
+            mTempMatrix.reset();
+            view.transformMatrixToGlobal(mTempMatrix);
+            builder.setMatrix(mTempMatrix);
+            builder.setInsertionMarkerLocation(
+                    /* horizontalPosition= */ view.isLayoutRtl() ? view.getWidth() : 0,
+                    /* lineTop= */ 0,
+                    /* lineBaseline= */ view.getHeight(),
+                    /* lineBottom= */ view.getHeight(),
+                    /* flags= */ 0);
+        }
+        return builder.build();
+    }
+
+    @Nullable
+    private static TextView findFirstTextViewDescendent(View view) {
+        if (view instanceof ViewGroup viewGroup) {
+            TextView textView;
+            for (int i = 0; i < viewGroup.getChildCount(); ++i) {
+                View child = viewGroup.getChildAt(i);
+                textView = (child instanceof TextView tv)
+                        ? tv : findFirstTextViewDescendent(viewGroup.getChildAt(i));
+                if (textView != null
+                        && textView.isAggregatedVisible()
+                        && (!TextUtils.isEmpty(textView.getText())
+                                || !TextUtils.isEmpty(textView.getHint()))) {
+                    return textView;
+                }
+            }
+        }
+        return null;
+    }
+
     /**
      * A class used to track the handwriting areas set by the Views.
      *
@@ -931,4 +997,35 @@
             return true;
         }
     }
+
+    private class DelegationCallback implements ConnectionlessHandwritingCallback {
+        private final View mView;
+        private final String mDelegatePackageName;
+
+        private DelegationCallback(View view, String delegatePackageName) {
+            mView = view;
+            mDelegatePackageName = delegatePackageName;
+        }
+
+        @Override
+        public void onResult(@NonNull CharSequence text) {
+            mView.getHandwritingDelegatorCallback().run();
+        }
+
+        @Override
+        public void onError(int errorCode) {
+            switch (errorCode) {
+                case CONNECTIONLESS_HANDWRITING_ERROR_NO_TEXT_RECOGNIZED:
+                    mView.getHandwritingDelegatorCallback().run();
+                    break;
+                case CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED:
+                    // Fall back to the old delegation flow
+                    mImm.prepareStylusHandwritingDelegation(mView, mDelegatePackageName);
+                    mView.getHandwritingDelegatorCallback().run();
+                    mState.mHasInitiatedHandwriting = false;
+                    mState.mHasPreparedHandwritingDelegation = true;
+                    break;
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 29cc859..c475f6b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -1098,4 +1098,7 @@
      * (ie. not handled by any window which can handle the drag).
      */
     void setUnhandledDragListener(IUnhandledDragListener listener);
+
+    boolean transferTouchGesture(in InputTransferToken transferFromToken,
+            in InputTransferToken transferToToken);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 55e49f8..d68a47c 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -370,11 +370,6 @@
      */
     boolean cancelDraw(IWindow window);
 
-    boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow);
-
-    boolean transferHostTouchGestureToEmbedded(IWindow hostWindow,
-        in InputTransferToken transferTouchToken);
-
     /**
      * Moves the focus to the adjacent window if there is one in the given direction. This can only
      * move the focus to the window in the same leaf task.
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 1dd9cbb..06a923a 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -293,12 +293,12 @@
         /**
          * Gets an {@link InputTransferToken} which can be used to request focus on the embedded
          * surface or to transfer touch gesture to the embedded surface.
-         * @return the InputTransferToken associated with {@link SurfacePackage}
-         * @see AttachedSurfaceControl#transferHostTouchGestureToEmbedded(SurfacePackage)
-         *
-         * @hide
+         * @return the InputTransferToken associated with {@link SurfacePackage} or {@code null} if
+         * the embedded hasn't set up its view or doesn't have input.
+         * @see WindowManager#transferTouchGesture(InputTransferToken, InputTransferToken)
          */
         @Nullable
+        @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
         public InputTransferToken getInputTransferToken() {
             return mInputTransferToken;
         }
@@ -577,9 +577,9 @@
     }
 
     /**
-     * Transfer the currently in progress touch gesture to the parent
-     * (if any) of this SurfaceControlViewHost. This requires that the
-     * SurfaceControlViewHost was created with an associated hostInputToken.
+     * Transfer the currently in progress touch gesture to the parent (if any) of this
+     * SurfaceControlViewHost. This requires that the SurfaceControlViewHost was created with an
+     * associated host {@link InputTransferToken}.
      *
      * @return Whether the touch stream was transferred.
      */
@@ -587,13 +587,14 @@
         if (mViewRoot == null) {
             return false;
         }
-
-        final IWindowSession realWm = WindowManagerGlobal.getWindowSession();
-        try {
-            return realWm.transferEmbeddedTouchFocusToHost(mViewRoot.mWindow);
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
+        final WindowManager wm =
+                (WindowManager) mViewRoot.mContext.getSystemService(Context.WINDOW_SERVICE);
+        InputTransferToken embeddedToken = getInputTransferToken();
+        InputTransferToken hostToken = mWm.mHostInputTransferToken;
+        if (embeddedToken == null || hostToken == null) {
+            Log.w(TAG, "Failed to transferTouchGestureToHost. Host or embedded token is null");
+            return false;
         }
-        return false;
+        return wm.transferTouchGesture(getInputTransferToken(), mWm.mHostInputTransferToken);
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 25ade62..73b6ed6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5638,7 +5638,7 @@
     private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
 
     @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
-    public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = 0;
+    public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN;
     @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
     public static final float REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE = -1;
     @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
@@ -33457,7 +33457,6 @@
         if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) {
             return FRAME_RATE_CATEGORY_NORMAL;
         }
-
         return mLastFrameRateCategory;
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 657c8e6..9474a69 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -27,6 +27,8 @@
 import static android.view.InsetsSource.ID_IME;
 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT;
+import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
+import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
 import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
 import static android.view.View.PFLAG_DRAW_ANIMATION;
 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
@@ -1031,6 +1033,15 @@
     private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100;
 
     /*
+     * The variables below are used to update frame rate category
+     */
+    private static final int FRAME_RATE_CATEGORY_COUNT = 5;
+    private int mFrameRateCategoryHighCount = 0;
+    private int mFrameRateCategoryHighHintCount = 0;
+    private int mFrameRateCategoryNormalCount = 0;
+    private int mFrameRateCategoryLowCount = 0;
+
+    /*
      * the variables below are used to determine whther a dVRR feature should be enabled
      */
 
@@ -4084,7 +4095,14 @@
         // when the values are applicable.
         setPreferredFrameRate(mPreferredFrameRate);
         setPreferredFrameRateCategory(mPreferredFrameRateCategory);
+        mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0
+                ? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount;
+        mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0
+                ? mFrameRateCategoryNormalCount - 1 : mFrameRateCategoryNormalCount;
+        mFrameRateCategoryLowCount = mFrameRateCategoryLowCount > 0
+                ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount;
         mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
+        mPreferredFrameRate = -1;
     }
 
     private void createSyncIfNeeded() {
@@ -12296,7 +12314,8 @@
         }
 
         try {
-            if (mLastPreferredFrameRate != preferredFrameRate) {
+            if (mLastPreferredFrameRate != preferredFrameRate
+                    && preferredFrameRate >= 0) {
                 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                     Trace.traceBegin(
                             Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
@@ -12346,7 +12365,25 @@
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
     public void votePreferredFrameRateCategory(int frameRateCategory) {
-        mPreferredFrameRateCategory = Math.max(mPreferredFrameRateCategory, frameRateCategory);
+        if (frameRateCategory == FRAME_RATE_CATEGORY_HIGH) {
+            mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
+        } else if (frameRateCategory == FRAME_RATE_CATEGORY_HIGH_HINT) {
+            mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT;
+        } else if (frameRateCategory == FRAME_RATE_CATEGORY_NORMAL) {
+            mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
+        } else if (frameRateCategory == FRAME_RATE_CATEGORY_LOW) {
+            mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT;
+        }
+
+        if (mFrameRateCategoryHighCount > 0) {
+            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
+        } else if (mFrameRateCategoryHighHintCount > 0) {
+            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
+        } else if (mFrameRateCategoryNormalCount > 0) {
+            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NORMAL;
+        } else if (mFrameRateCategoryLowCount > 0) {
+            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
+        }
         mHasInvalidation = true;
     }
 
@@ -12368,13 +12405,7 @@
             return;
         }
 
-        if (mPreferredFrameRate == 0) {
-            mPreferredFrameRate = frameRate;
-        } else if (frameRate > 60 || mPreferredFrameRate > 60) {
-            mPreferredFrameRate = Math.max(mPreferredFrameRate, frameRate);
-        } else if (mPreferredFrameRate != frameRate) {
-            mPreferredFrameRate = 60;
-        }
+        mPreferredFrameRate = Math.max(mPreferredFrameRate, frameRate);
 
         mHasInvalidation = true;
         mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
@@ -12403,7 +12434,7 @@
      */
     @VisibleForTesting
     public float getPreferredFrameRate() {
-        return mPreferredFrameRate;
+        return mPreferredFrameRate >= 0 ? mPreferredFrameRate : mLastPreferredFrameRate;
     }
 
     /**
@@ -12431,19 +12462,6 @@
                 boostTimeOut);
     }
 
-    @Override
-    public boolean transferHostTouchGestureToEmbedded(
-            @NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) {
-        final IWindowSession realWm = WindowManagerGlobal.getWindowSession();
-        try {
-            return realWm.transferHostTouchGestureToEmbedded(mWindow,
-                    surfacePackage.getInputTransferToken());
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
-        }
-        return false;
-    }
-
     /**
      * Set the default back key callback for windowless window, to forward the back key event
      * to host app.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0302a0d..e4be016 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1548,6 +1548,48 @@
             "android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI";
 
     /**
+     * Application or Activity level
+     * {@link android.content.pm.PackageManager.Property PackageManager.Property} to provide any
+     * preferences for showing all or specific Activities on small cover displays of foldable
+     * style devices.
+     *
+     * <p>The only supported value for the property is {@link #COMPAT_SMALL_COVER_SCREEN_OPT_IN}.
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN"
+     *     android:value=1 <!-- COMPAT_COVER_SCREEN_OPT_IN -->/&gt;
+     * &lt;/application&gt;
+     * </pre>
+     */
+    @FlaggedApi(Flags.FLAG_COVER_DISPLAY_OPT_IN)
+    String PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN =
+            "android.window.PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN";
+
+    /**
+     * Value applicable for the {@link #PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN} property to
+     * provide a signal to the system that an application or its specific activities explicitly
+     * opt into being displayed on small foldable device cover screens that measure at least 1.5
+     * inches for the shorter dimension and at least 2.4 inches for the longer dimension.
+     */
+    @CompatSmallScreenPolicy
+    @FlaggedApi(Flags.FLAG_COVER_DISPLAY_OPT_IN)
+    int COMPAT_SMALL_COVER_SCREEN_OPT_IN = 1;
+
+    /**
+     * @hide
+     */
+    @IntDef({
+            COMPAT_SMALL_COVER_SCREEN_OPT_IN,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface CompatSmallScreenPolicy {}
+
+
+
+    /**
      * Request for app's keyboard shortcuts to be retrieved asynchronously.
      *
      * @param receiver The callback to be triggered when the result is ready.
@@ -6115,12 +6157,15 @@
      *                               rendering Choreographer.
      * @param receiver               The SurfaceControlInputReceiver that will receive the input
      *                               events
+     * @return Returns the {@link InputTransferToken} that can be used to transfer touch gesture
+     * to or from other windows.
      */
     @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
-    default void registerBatchedSurfaceControlInputReceiver(int displayId,
+    @NonNull
+    default InputTransferToken registerBatchedSurfaceControlInputReceiver(int displayId,
             @NonNull InputTransferToken hostInputTransferToken,
-            @NonNull SurfaceControl surfaceControl,
-            @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
+            @NonNull SurfaceControl surfaceControl, @NonNull Choreographer choreographer,
+            @NonNull SurfaceControlInputReceiver receiver) {
         throw new UnsupportedOperationException(
                 "registerBatchedSurfaceControlInputReceiver is not implemented");
     }
@@ -6145,9 +6190,12 @@
      * @param looper                 The looper to use when invoking callbacks.
      * @param receiver               The SurfaceControlInputReceiver that will receive the input
      *                               events.
+     * @return Returns the {@link InputTransferToken} that can be used to transfer touch gesture
+     * to or from other windows.
      */
     @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
-    default void registerUnbatchedSurfaceControlInputReceiver(int displayId,
+    @NonNull
+    default InputTransferToken registerUnbatchedSurfaceControlInputReceiver(int displayId,
             @NonNull InputTransferToken hostInputTransferToken,
             @NonNull SurfaceControl surfaceControl, @NonNull Looper looper,
             @NonNull SurfaceControlInputReceiver receiver) {
@@ -6196,6 +6244,70 @@
     }
 
     /**
+     * Transfer the currently in progress touch gesture from the transferFromToken to the
+     * transferToToken.
+     * <p><br>
+     * This requires that the fromToken and toToken are associated with each other. The association
+     * can be done different ways, depending on how the embedded window is created.
+     * <ul>
+     * <li>
+     * Creating a {@link SurfaceControlViewHost} and passing the host's
+     * {@link InputTransferToken} for
+     * {@link SurfaceControlViewHost#SurfaceControlViewHost(Context, Display, InputTransferToken)}.
+     * </li>
+     * <li>
+     * Registering a SurfaceControl for input and passing the host's token to either
+     * {@link #registerBatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
+     * Choreographer, SurfaceControlInputReceiver)} or
+     * {@link #registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken,
+     * SurfaceControl, Looper, SurfaceControlInputReceiver)}.
+     * </li>
+     * </ul>
+     * <p>
+     * The host is likely to be an {@link AttachedSurfaceControl} so the host token can be
+     * retrieved via {@link AttachedSurfaceControl#getInputTransferToken()}.
+     * <p><br>
+     * Only the window currently receiving touch is allowed to transfer the gesture so if the caller
+     * attempts to transfer touch gesture from a token that doesn't have touch, it will fail the
+     * transfer.
+     * <p><br>
+     * When the host wants to transfer touch gesture to the embedded, it can retrieve the embedded
+     * token via {@link SurfaceControlViewHost.SurfacePackage#getInputTransferToken()} or use the
+     * value returned from either
+     * {@link #registerBatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
+     * Choreographer, SurfaceControlInputReceiver)} or
+     * {@link #registerUnbatchedSurfaceControlInputReceiver(int, InputTransferToken, SurfaceControl,
+     * Looper, SurfaceControlInputReceiver)} and pass its own token as the transferFromToken.
+     * <p>
+     * When the embedded wants to transfer touch gesture to the host, it can pass in its own
+     * token as the transferFromToken and use the associated host's {@link InputTransferToken} as
+     * the transferToToken
+     * <p><br>
+     * When the touch is transferred, the window currently receiving touch gets an ACTION_CANCEL
+     * and does not receive any further input events for this gesture.
+     * <p>
+     * The transferred-to window receives an ACTION_DOWN event and then the remainder of the input
+     * events for this gesture. It does not receive any of the previous events of this gesture that
+     * the originating window received.
+     * <p>
+     * The transferTouchGesture API only works for the current gesture. When a new gesture
+     * arrives, input dispatcher will do a new round of hit testing. So, if the host window is
+     * still the first thing that's being touched, then it will receive the new gesture again. It
+     * will again be up to the host to transfer this new gesture to the embedded.
+     *
+     * @param transferFromToken the InputTransferToken for the currently active gesture
+     * @param transferToToken   the InputTransferToken to transfer the gesture to.
+     * @return Whether the touch stream was transferred.
+     * @see android.view.SurfaceControlViewHost.SurfacePackage#getInputTransferToken()
+     * @see AttachedSurfaceControl#getInputTransferToken()
+     */
+    @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+    default boolean transferTouchGesture(@NonNull InputTransferToken transferFromToken,
+            @NonNull InputTransferToken transferToToken) {
+        throw new UnsupportedOperationException("transferTouchGesture is not implemented");
+    }
+
+    /**
      * @hide
      */
     default @NonNull IBinder getDefaultToken() {
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 1428963..584219a 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -839,14 +839,15 @@
         mTrustedPresentationListener.removeListener(listener);
     }
 
-    void registerBatchedSurfaceControlInputReceiver(int displayId,
+    InputTransferToken registerBatchedSurfaceControlInputReceiver(int displayId,
             @NonNull InputTransferToken hostToken, @NonNull SurfaceControl surfaceControl,
             @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
         IBinder clientToken = new Binder();
+        InputTransferToken inputTransferToken = new InputTransferToken();
         InputChannel inputChannel = new InputChannel();
         try {
             WindowManagerGlobal.getWindowSession().grantInputChannel(displayId, surfaceControl,
-                    clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null, null,
+                    clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null, inputTransferToken,
                     surfaceControl.getName(), inputChannel);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to create input channel", e);
@@ -865,16 +866,18 @@
                                 }
                             }));
         }
+        return inputTransferToken;
     }
 
-    void registerUnbatchedSurfaceControlInputReceiver(int displayId,
+    InputTransferToken registerUnbatchedSurfaceControlInputReceiver(int displayId,
             @NonNull InputTransferToken hostToken, @NonNull SurfaceControl surfaceControl,
             @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
         IBinder clientToken = new Binder();
+        InputTransferToken inputTransferToken = new InputTransferToken();
         InputChannel inputChannel = new InputChannel();
         try {
             WindowManagerGlobal.getWindowSession().grantInputChannel(displayId, surfaceControl,
-                    clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null, null,
+                    clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null, inputTransferToken,
                     surfaceControl.getName(), inputChannel);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to create input channel", e);
@@ -892,6 +895,7 @@
                                 }
                             }));
         }
+        return inputTransferToken;
     }
 
     void unregisterSurfaceControlInputReceiver(SurfaceControl surfaceControl) {
@@ -930,6 +934,17 @@
         return surfaceControlInputReceiverInfo.mClientToken;
     }
 
+    boolean transferTouchGesture(InputTransferToken transferFromToken,
+            InputTransferToken transferToToken) {
+        try {
+            return getWindowManagerService().transferTouchGesture(transferFromToken,
+                    transferToToken);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+        return false;
+    }
+
     private final class TrustedPresentationListener extends
             ITrustedPresentationListener.Stub {
         private static int sId = 0;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 1e3d062..8972228 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -533,22 +533,24 @@
         mGlobal.unregisterTrustedPresentationListener(listener);
     }
 
+    @NonNull
     @Override
-    public void registerBatchedSurfaceControlInputReceiver(int displayId,
+    public InputTransferToken registerBatchedSurfaceControlInputReceiver(int displayId,
             @NonNull InputTransferToken hostInputTransferToken,
             @NonNull SurfaceControl surfaceControl, @NonNull Choreographer choreographer,
             @NonNull SurfaceControlInputReceiver receiver) {
-        mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostInputTransferToken,
+        return mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostInputTransferToken,
                 surfaceControl, choreographer, receiver);
     }
 
+    @NonNull
     @Override
-    public void registerUnbatchedSurfaceControlInputReceiver(int displayId,
+    public InputTransferToken registerUnbatchedSurfaceControlInputReceiver(int displayId,
             @NonNull InputTransferToken hostInputTransferToken,
             @NonNull SurfaceControl surfaceControl, @NonNull Looper looper,
             @NonNull SurfaceControlInputReceiver receiver) {
-        mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostInputTransferToken,
-                surfaceControl, looper, receiver);
+        return mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId,
+                hostInputTransferToken, surfaceControl, looper, receiver);
     }
 
     @Override
@@ -563,6 +565,14 @@
     }
 
     @Override
+    public boolean transferTouchGesture(@NonNull InputTransferToken transferFromToken,
+            @NonNull InputTransferToken transferToToken) {
+        Objects.requireNonNull(transferFromToken);
+        Objects.requireNonNull(transferToToken);
+        return mGlobal.transferTouchGesture(transferFromToken, transferToToken);
+    }
+
+    @Override
     public @ScreenRecordingState int addScreenRecordingCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull Consumer<@ScreenRecordingState Integer> callback) {
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 3f1ae51..2b2c507 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -651,21 +651,6 @@
     }
 
     @Override
-    public boolean transferEmbeddedTouchFocusToHost(IWindow window) {
-        Log.e(TAG, "Received request to transferEmbeddedTouch focus on WindowlessWindowManager" +
-            " we shouldn't get here!");
-        return false;
-    }
-
-    @Override
-    public boolean transferHostTouchGestureToEmbedded(IWindow hostWindow,
-            InputTransferToken embeddedInputToken) {
-        Log.e(TAG, "Received request to transferHostTouchGestureToEmbedded on"
-                + " WindowlessWindowManager. We shouldn't get here!");
-        return false;
-    }
-
-    @Override
     public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) {
         Log.e(TAG, "Received request to moveFocusToAdjacentWindow on"
                 + " WindowlessWindowManager. We shouldn't get here!");
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 57e4e6a..9847cb1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -181,6 +181,7 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewHierarchyEncoder;
 import android.view.ViewParent;
@@ -866,6 +867,7 @@
     private final boolean mUseTextPaddingForUiTranslation;
 
     private boolean mUseBoundsForWidth;
+    private boolean mShiftDrawingOffsetForStartOverhang;
     @Nullable private Paint.FontMetrics mMinimumFontMetrics;
     @Nullable private Paint.FontMetrics mLocalePreferredFontMetrics;
     private boolean mUseLocalePreferredLineHeightForMinimum;
@@ -1621,6 +1623,10 @@
                     hasUseBoundForWidthValue = true;
                     break;
                 case com.android.internal.R.styleable
+                        .TextView_shiftDrawingOffsetForStartOverhang:
+                    mShiftDrawingOffsetForStartOverhang = a.getBoolean(attr, false);
+                    break;
+                case com.android.internal.R.styleable
                         .TextView_useLocalePreferredLineHeightForMinimum:
                     mUseLocalePreferredLineHeightForMinimum = a.getBoolean(attr, false);
                     break;
@@ -4922,6 +4928,8 @@
      * @param useBoundsForWidth true for using bounding box for width. false for using advances for
      *                          width.
      * @see #getUseBoundsForWidth()
+     * @see #setShiftDrawingOffsetForStartOverhang(boolean)
+     * @see #getShiftDrawingOffsetForStartOverhang()
      */
     @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
     public void setUseBoundsForWidth(boolean useBoundsForWidth) {
@@ -4939,6 +4947,8 @@
      * Returns true if using bounding box as a width, false for using advance as a width.
      *
      * @see #setUseBoundsForWidth(boolean)
+     * @see #setShiftDrawingOffsetForStartOverhang(boolean)
+     * @see #getShiftDrawingOffsetForStartOverhang()
      * @return True if using bounding box for width, false if using advance for width.
      */
     @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
@@ -4947,6 +4957,53 @@
     }
 
     /**
+     * Set true for shifting the drawing x offset for showing overhang at the start position.
+     *
+     * This flag is ignored if the {@link #getUseBoundsForWidth()} is false.
+     *
+     * If this value is false, the TextView draws text from the zero even if there is a glyph stroke
+     * in a region where the x coordinate is negative. TextView clips the stroke in the region where
+     * the X coordinate is negative unless the parents has {@link ViewGroup#getClipChildren()} to
+     * true. This is useful for aligning multiple TextViews vertically.
+     *
+     * If this value is true, the TextView draws text with shifting the x coordinate of the drawing
+     * bounding box. This prevents the clipping even if the parents doesn't have
+     * {@link ViewGroup#getClipChildren()} to true.
+     *
+     * This value is false by default.
+     *
+     * @param shiftDrawingOffsetForStartOverhang true for shifting the drawing offset for showing
+     *                                           the stroke that is in the region whre the x
+     *                                           coorinate is negative.
+     * @see #setUseBoundsForWidth(boolean)
+     * @see #getUseBoundsForWidth()
+     */
+    @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+    public void setShiftDrawingOffsetForStartOverhang(boolean shiftDrawingOffsetForStartOverhang) {
+        if (mShiftDrawingOffsetForStartOverhang != shiftDrawingOffsetForStartOverhang) {
+            mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
+            if (mLayout != null) {
+                nullLayouts();
+                requestLayout();
+                invalidate();
+            }
+        }
+    }
+
+    /**
+     * Returns true if shifting the drawing x offset for start overhang.
+     *
+     * @see #setShiftDrawingOffsetForStartOverhang(boolean)
+     * @see #setUseBoundsForWidth(boolean)
+     * @see #getUseBoundsForWidth()
+     * @return True if shifting the drawing x offset for start overhang.
+     */
+    @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+    public boolean getShiftDrawingOffsetForStartOverhang() {
+        return mShiftDrawingOffsetForStartOverhang;
+    }
+
+    /**
      * Set the minimum font metrics used for line spacing.
      *
      * <p>
@@ -11001,6 +11058,7 @@
                                 null,
                                 boring,
                                 mUseBoundsForWidth,
+                                mShiftDrawingOffsetForStartOverhang,
                                 getResolvedMinimumFontMetrics());
                     }
 
@@ -11028,6 +11086,7 @@
                                 effectiveEllipsize,
                                 boring,
                                 mUseBoundsForWidth,
+                                mShiftDrawingOffsetForStartOverhang,
                                 getResolvedMinimumFontMetrics());
                     }
                 }
diff --git a/core/java/android/window/InputTransferToken.java b/core/java/android/window/InputTransferToken.java
index bed0e0e..e572853 100644
--- a/core/java/android/window/InputTransferToken.java
+++ b/core/java/android/window/InputTransferToken.java
@@ -20,8 +20,12 @@
 import android.annotation.NonNull;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.Choreographer;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlInputReceiver;
 import android.view.SurfaceControlViewHost;
 
 import com.android.window.flags.Flags;
@@ -31,6 +35,19 @@
 /**
  * A token that can be used to request focus on or to transfer touch gesture to a
  * {@link SurfaceControlViewHost} or {@link android.view.SurfaceControl} that has an input channel.
+ * <p>
+ * The {@link android.view.SurfaceControl} needs to have been registered for input via
+ * {@link android.view.WindowManager#registerUnbatchedSurfaceControlInputReceiver(int,
+ * InputTransferToken, SurfaceControl, Looper, SurfaceControlInputReceiver)} or
+ * {@link android.view.WindowManager#registerBatchedSurfaceControlInputReceiver(int,
+ * InputTransferToken, SurfaceControl, Choreographer, SurfaceControlInputReceiver)} and the
+ * returned token can be used to call
+ * {@link android.view.WindowManager#transferTouchGesture(InputTransferToken, InputTransferToken)}
+ * <p>
+ * For {@link SurfaceControlViewHost}, the token can be retrieved via
+ * {@link SurfaceControlViewHost.SurfacePackage#getInputTransferToken()}
+ *
+ * @see android.view.WindowManager#transferTouchGesture(InputTransferToken, InputTransferToken)
  */
 @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
 public final class InputTransferToken implements Parcelable {
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 3ffa274..8b3bd97 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -20,13 +20,6 @@
 
 flag {
     namespace: "window_surfaces"
-    name: "transfer_gesture_to_embedded"
-    description: "Enable public API for Window Surfaces"
-    bug: "287076178"
-}
-
-flag {
-    namespace: "window_surfaces"
     name: "delete_capture_display"
     description: "Delete uses of ScreenCapture#captureDisplay"
     is_fixed_read_only: true
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index bc63881..ce74848 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -69,4 +69,12 @@
     name: "embedded_activity_back_nav_flag"
     description: "Refines embedded activity back navigation behavior"
     bug: "293642394"
+}
+
+flag {
+    namespace: "windowing_sdk"
+    name: "cover_display_opt_in"
+    description: "Properties to allow apps and activities to opt-in to cover display rendering"
+    bug: "312530526"
+    is_fixed_read_only: true
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 3a321e5..3ec7064 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -162,4 +162,5 @@
             int attributionFlags, int attributionChainId);
     void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName,
             @nullable String attributionTag, int virtualDeviceId);
+   List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId);
 }
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index d433ca3..73df5e8 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -408,6 +408,7 @@
     // Derived fields
     private long mLongVersionCode;
     private int mLocaleConfigRes;
+    private boolean mAllowCrossUidActivitySwitchFromBelow;
 
     private List<AndroidPackageSplit> mSplits;
 
@@ -1542,6 +1543,11 @@
     }
 
     @Override
+    public boolean isAllowCrossUidActivitySwitchFromBelow() {
+        return mAllowCrossUidActivitySwitchFromBelow;
+    }
+
+    @Override
     public boolean hasPreserveLegacyExternalStorage() {
         return getBoolean(Booleans.PRESERVE_LEGACY_EXTERNAL_STORAGE);
     }
@@ -2199,6 +2205,12 @@
     }
 
     @Override
+    public ParsingPackage setAllowCrossUidActivitySwitchFromBelow(boolean value) {
+        mAllowCrossUidActivitySwitchFromBelow = value;
+        return this;
+    }
+
+    @Override
     public PackageImpl setResourceOverlay(boolean value) {
         return setBoolean(Booleans.OVERLAY, value);
     }
@@ -2656,6 +2668,7 @@
         if (!mKnownActivityEmbeddingCerts.isEmpty()) {
             appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts);
         }
+        appInfo.allowCrossUidActivitySwitchFromBelow = mAllowCrossUidActivitySwitchFromBelow;
 
         return appInfo;
     }
@@ -3250,6 +3263,7 @@
         dest.writeInt(this.uid);
         dest.writeLong(this.mBooleans);
         dest.writeLong(this.mBooleans2);
+        dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow);
     }
 
     public PackageImpl(Parcel in) {
@@ -3411,6 +3425,7 @@
         this.uid = in.readInt();
         this.mBooleans = in.readLong();
         this.mBooleans2 = in.readLong();
+        this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean();
 
         assignDerivedFields();
         assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index ef106e0..5d185af 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -374,6 +374,9 @@
 
     ParsingPackage setZygotePreloadName(String zygotePreloadName);
 
+    ParsingPackage setAllowCrossUidActivitySwitchFromBelow(
+            boolean allowCrossUidActivitySwitchFromBelow);
+
     ParsingPackage sortActivities();
 
     ParsingPackage sortReceivers();
@@ -518,6 +521,8 @@
     @Nullable
     String getZygotePreloadName();
 
+    boolean isAllowCrossUidActivitySwitchFromBelow();
+
     boolean isBackupAllowed();
 
     boolean isTaskReparentingAllowed();
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index e0fdbc6..2e6053d 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -2374,8 +2374,10 @@
                 .setRestrictedAccountType(string(R.styleable.AndroidManifestApplication_restrictedAccountType, sa))
                 .setZygotePreloadName(string(R.styleable.AndroidManifestApplication_zygotePreloadName, sa))
                 // Non-Config String
-                .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa));
-        // CHECKSTYLE:on
+                .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa))
+                .setAllowCrossUidActivitySwitchFromBelow(bool(true, R.styleable.AndroidManifestApplication_allowCrossUidActivitySwitchFromBelow, sa));
+
+       // CHECKSTYLE:on
         //@formatter:on
     }
 
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b5b3a48..e46b8d7 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1615,7 +1615,8 @@
                         STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
                         STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
                         STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT,
-                        SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED})
+                        SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED,
+                        SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST})
         @Retention(RetentionPolicy.SOURCE)
         public @interface StrongAuthFlags {}
 
@@ -1641,7 +1642,8 @@
 
         /**
          * Strong authentication is required because the user has been locked out after too many
-         * attempts.
+         * attempts using primary auth methods (i.e. PIN/pattern/password) from the lock screen,
+         * Android Settings, and BiometricPrompt where user authentication is required.
          */
         public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
 
@@ -1674,12 +1676,23 @@
         public static final int SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED = 0x100;
 
         /**
+         * Some authentication is required because adaptive auth has requested to lock device due to
+         * repeated failed primary auth (i.e. PIN/pattern/password) or biometric auth attempts which
+         * can come from Android Settings or BiometricPrompt where user authentication is required,
+         * in addition to from the lock screen. When a risk is determined, adaptive auth will
+         * proactively prompt the lock screen and will require users to re-enter the device with
+         * either primary auth or biometric auth (if not prohibited by other flags).
+         */
+        public static final int SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST = 0x200;
+
+        /**
          * Strong auth flags that do not prevent biometric methods from being accepted as auth.
          * If any other flags are set, biometric authentication is disabled.
          */
         private static final int ALLOWING_BIOMETRIC = STRONG_AUTH_NOT_REQUIRED
                 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
-                | SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED;
+                | SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED
+                | SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
 
         private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
         private final H mHandler;
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index 096f246..d430fe3 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -1507,4 +1507,11 @@
      * @hide
      */
     boolean isVisibleToInstantApps();
+
+    /**
+     * @see ApplicationInfo#allowCrossUidActivitySwitchFromBelow
+     * @see R.styleable#AndroidManifestApplication_allowCrossUidActivitySwitchFromBelow
+     * @hide
+     */
+    boolean isAllowCrossUidActivitySwitchFromBelow();
 }
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index b9905e8..b7408a4 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -113,6 +113,7 @@
         optional int32 enable_gwp_asan = 19;
         optional int32 enable_memtag = 20;
         optional bool native_heap_zero_init = 21;
+        optional bool allow_cross_uid_activity_switch_from_below = 22;
     }
     optional Detail detail = 17;
     repeated string overlay_paths = 18;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e7df19c..71f06f1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3690,6 +3690,14 @@
     <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING"
                 android:protectionLevel="internal|role" />
 
+    <!-- Allows an application to use audit logging API.
+        @hide
+        @SystemApi
+        @FlaggedApi("android.app.admin.flags.security_log_v2_enabled")
+    -->
+    <permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING"
+        android:protectionLevel="internal|role" />
+
     <!-- Allows an application to set policy related to system updates.
         <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
         required to call APIs protected by this permission on users different to the calling user.
@@ -3793,6 +3801,14 @@
     <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK"
                 android:protectionLevel="internal|role" />
 
+    <!-- Allows an application to manage policy related to theft detection.
+        @FlaggedApi("android.app.admin.flags.device_theft_api_enabled")
+        @hide
+        @SystemApi
+    -->
+    <permission android:name="android.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION"
+                android:protectionLevel="internal|role" />
+
     <!-- Allows an application to manage policy related to system apps.
         <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
         APIs protected by this permission on users different to the calling user.
@@ -3830,6 +3846,24 @@
     <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS"
         android:protectionLevel="internal|role" />
 
+    <!-- Allows an application to manage policy related to block package uninstallation.
+        @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
+    -->
+    <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL"
+        android:protectionLevel="internal|role" />
+
+    <!-- Allows an application to manage policy related to camera toggle.
+        @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
+    -->
+    <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE"
+        android:protectionLevel="internal|role" />
+
+    <!-- Allows an application to manage policy related to microphone toggle.
+        @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
+    -->
+    <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE"
+        android:protectionLevel="internal|role" />
+
     <!-- Allows an application to set device policies outside the current user
         that are critical for securing data within the current user.
         <p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
@@ -6884,13 +6918,10 @@
     <permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to manage media projection sessions, by showing the permission dialog
-         to the user and creating a new token for each capture session.
-         @FlaggedApi("com.android.media.flags.limit_manage_media_projection")
-         @SystemApi Only granted to apps holding role SYSTEM_UI.
+    <!-- Api Allows an application to manage media projection sessions.
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"
-        android:protectionLevel="internal|role" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to read install sessions
          @hide This is not a third-party API (intended for system apps). -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4ee03de..cc6460e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5891,6 +5891,17 @@
           use glyph bound's as a source of text width.  -->
         <!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") -->
         <attr name="useBoundsForWidth" format="boolean" />
+
+
+        <!-- Whether to shift the drawing offset for prevent clipping start drawing offset.
+          This value is ignored when the useBoundsForWidth attribute is false.
+
+          If this value is false, the TextView draws text from the zero X coordinate. This is
+          useful for aligning multiple TextViews vertically.
+          If this value is true, the TextView shift the drawing offset not to clip the
+          stroke in the region where the X coordinate is negative. -->
+        <!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") -->
+        <attr name="shiftDrawingOffsetForStartOverhang" format="boolean" />
         <!-- Whether to use the locale preferred line height for the minimum line height.
 
           This flag is useful for preventing jitter of entering letters into empty EditText.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 734ff8d..b2e0be7c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1919,6 +1919,12 @@
              try to load its code when launching components.  The default is true
              for normal behavior. -->
         <attr name="hasCode" format="boolean" />
+        <!-- Specifies if activities can be launched on top of this application by activities from
+             other applications in the same task. If set to false, activity launches which would
+             replace this application with another when in the user's view will be blocked.
+             The default is true. -->
+        <!-- @FlaggedApi("android.security.asm_restrictions_enabled") -->
+        <attr name="allowCrossUidActivitySwitchFromBelow" format="boolean" />
         <attr name="persistent" />
         <attr name="persistentWhenFeatureAvailable" />
         <attr name="requiredForAllUsers" />
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index dcb6bb0..8af8cb8 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -159,6 +159,12 @@
     <public name="contentSensitivity" />
     <!-- @FlaggedApi("android.view.inputmethod.connectionless_handwriting") -->
     <public name="supportsConnectionlessStylusHandwriting" />
+    <!-- @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") -->
+    <public name="defaultToObserveMode"/>
+    <!-- @FlaggedApi("android.security.asm_restrictions_enabled") -->
+    <public name="allowCrossUidActivitySwitchFromBelow"/>
+    <!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") -->
+    <public name="shiftDrawingOffsetForStartOverhang" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01bc0000">
diff --git a/core/tests/BroadcastRadioTests/TEST_MAPPING b/core/tests/BroadcastRadioTests/TEST_MAPPING
index b085a27..5637063 100644
--- a/core/tests/BroadcastRadioTests/TEST_MAPPING
+++ b/core/tests/BroadcastRadioTests/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "postsubmit": [
+  "presubmit": [
     {
       "name": "BroadcastRadioTests"
     }
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 2327b20..48ef7e6 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -40,6 +40,7 @@
 import android.app.Application;
 import android.app.IApplicationThread;
 import android.app.PictureInPictureParams;
+import android.app.PictureInPictureUiState;
 import android.app.ResourcesManager;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ActivityLifecycleItem;
@@ -706,6 +707,9 @@
         final TestActivity activity = mActivityTestRule.launchActivity(startIntent);
         final ActivityThread activityThread = activity.getActivityThread();
         final ActivityClientRecord r = getActivityClientRecord(activity);
+        if (android.app.Flags.enablePipUiStateCallbackOnEntering()) {
+            activity.mPipUiStateLatch = new CountDownLatch(1);
+        }
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             activityThread.handlePictureInPictureRequested(r);
@@ -940,6 +944,11 @@
          * latch reaches 0.
          */
         volatile CountDownLatch mConfigLatch;
+        /**
+         * A latch used to notify tests that we're about to wait for the
+         * onPictureInPictureUiStateChanged callback.
+         */
+        volatile CountDownLatch mPipUiStateLatch;
 
         @Override
         protected void onCreate(Bundle savedInstanceState) {
@@ -974,6 +983,14 @@
             if (getIntent().getBooleanExtra(PIP_REQUESTED_OVERRIDE_ENTER, false)) {
                 enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
                 mPipEntered = true;
+                // Await for onPictureInPictureUiStateChanged callback if applicable
+                if (mPipUiStateLatch != null) {
+                    try {
+                        mPipUiStateLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
+                    } catch (InterruptedException e) {
+                        throw new IllegalStateException(e);
+                    }
+                }
                 return true;
             } else if (getIntent().getBooleanExtra(PIP_REQUESTED_OVERRIDE_SKIP, false)) {
                 mPipEnterSkipped = true;
@@ -982,6 +999,13 @@
             return super.onPictureInPictureRequested();
         }
 
+        @Override
+        public void onPictureInPictureUiStateChanged(PictureInPictureUiState pipState) {
+            if (mPipUiStateLatch != null && pipState.isEnteringPip()) {
+                mPipUiStateLatch.countDown();
+            }
+        }
+
         boolean pipRequested() {
             return mPipRequested;
         }
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 0657e4b..433d353 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -660,10 +660,22 @@
     public void votePreferredFrameRate_voteFrameRateCategory_aggregate() {
         View view = new View(sContext);
         attachViewToWindow(view);
+        ViewRootImpl viewRootImpl = view.getViewRootImpl();
         sInstrumentation.runOnMainSync(() -> {
-            ViewRootImpl viewRootImpl = view.getViewRootImpl();
             assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
                     FRAME_RATE_CATEGORY_NO_PREFERENCE);
+        });
+
+        // reset the frame rate category counts
+        for (int i = 0; i < 5; i++) {
+            sInstrumentation.runOnMainSync(() -> {
+                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+                view.invalidate();
+            });
+            sInstrumentation.waitForIdleSync();
+        }
+
+        sInstrumentation.runOnMainSync(() -> {
             viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_LOW);
             assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
             viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_NORMAL);
@@ -699,6 +711,8 @@
             viewRootImpl.votePreferredFrameRate(24);
             assertEquals(viewRootImpl.getPreferredFrameRate(), 24, 0.1);
             viewRootImpl.votePreferredFrameRate(30);
+            assertEquals(viewRootImpl.getPreferredFrameRate(), 30, 0.1);
+            viewRootImpl.votePreferredFrameRate(60);
             assertEquals(viewRootImpl.getPreferredFrameRate(), 60, 0.1);
             viewRootImpl.votePreferredFrameRate(120);
             assertEquals(viewRootImpl.getPreferredFrameRate(), 120, 0.1);
@@ -721,6 +735,18 @@
         sInstrumentation.runOnMainSync(() -> {
             assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
                     FRAME_RATE_CATEGORY_NO_PREFERENCE);
+        });
+
+        // reset the frame rate category counts
+        for (int i = 0; i < 5; i++) {
+            sInstrumentation.runOnMainSync(() -> {
+                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+                view.invalidate();
+            });
+            sInstrumentation.waitForIdleSync();
+        }
+
+        sInstrumentation.runOnMainSync(() -> {
             view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_LOW);
             view.invalidate();
             assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
@@ -847,7 +873,18 @@
             assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
                     FRAME_RATE_CATEGORY_NO_PREFERENCE);
             assertEquals(viewRootImpl.getPreferredFrameRate(), frameRate, 0.1);
+        });
 
+        // reset the frame rate category counts
+        for (int i = 0; i < 5; i++) {
+            sInstrumentation.runOnMainSync(() -> {
+                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+                view.invalidate();
+            });
+            sInstrumentation.waitForIdleSync();
+        }
+
+        sInstrumentation.runOnMainSync(() -> {
             view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_LOW);
             view.invalidate();
             assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
@@ -882,18 +919,6 @@
 
         ViewRootImpl viewRootImpl = view.getViewRootImpl();
 
-        // Frequent update
-        sInstrumentation.runOnMainSync(() -> {
-            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
-                    FRAME_RATE_CATEGORY_NO_PREFERENCE);
-            view.invalidate();
-            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
-            view.invalidate();
-            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
-            view.invalidate();
-            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
-        });
-
         // In transistion from frequent update to infrequent update
         Thread.sleep(delay);
         sInstrumentation.runOnMainSync(() -> {
@@ -901,9 +926,28 @@
             assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
         });
 
+        // reset the frame rate category counts
+        for (int i = 0; i < 5; i++) {
+            sInstrumentation.runOnMainSync(() -> {
+                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+                view.invalidate();
+            });
+            sInstrumentation.waitForIdleSync();
+        }
+
+        // In transistion from frequent update to infrequent update
+        Thread.sleep(delay);
+        sInstrumentation.runOnMainSync(() -> {
+            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+            view.invalidate();
+            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+                    FRAME_RATE_CATEGORY_NO_PREFERENCE);
+        });
+
         // Infrequent update
         Thread.sleep(delay);
         sInstrumentation.runOnMainSync(() -> {
+            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT);
             view.invalidate();
             assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL);
         });
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index c8cbb98..42e3387 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2077,6 +2077,12 @@
       "group": "WM_DEBUG_LOCKTASK",
       "at": "com\/android\/server\/wm\/LockTaskController.java"
     },
+    "-315778658": {
+      "message": "transferTouchGesture failed because args transferFromToken or transferToToken is null",
+      "level": "ERROR",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
     "-312353598": {
       "message": "Executing finish of activity: %s",
       "level": "VERBOSE",
@@ -2293,12 +2299,6 @@
       "group": "WM_DEBUG_ANIM",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
-    "-90559682": {
-      "message": "Config is skipping already pausing %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "-87705714": {
       "message": "findFocusedWindow: focusedApp=null using new focus @ %s",
       "level": "VERBOSE",
@@ -3547,12 +3547,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "1011462000": {
-      "message": "Re-launching after pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
     "1015746067": {
       "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
       "level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index dffcc6d..b5ea1b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -24,6 +24,7 @@
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
 import static android.view.WindowManager.TRANSIT_SLEEP;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
 
 import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
 
@@ -929,7 +930,14 @@
                 Slog.e(TAG, "Duplicate call to finish");
                 return;
             }
-            if (!toHome) {
+
+            boolean returningToApp = !toHome
+                    && !mWillFinishToHome
+                    && mPausingTasks != null
+                    && mState == STATE_NORMAL;
+            if (returningToApp && allAppsAreTranslucent(mPausingTasks)) {
+                mHomeTransitionObserver.notifyHomeVisibilityChanged(true);
+            } else if (!toHome) {
                 // For some transitions, we may have notified home activity that it became visible.
                 // We need to notify the observer that we are no longer going home.
                 mHomeTransitionObserver.notifyHomeVisibilityChanged(false);
@@ -948,7 +956,7 @@
                 if (toHome) wct.reorder(mRecentsTask, true /* toTop */);
                 else wct.restoreTransientOrder(mRecentsTask);
             }
-            if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) {
+            if (returningToApp) {
                 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "  returning to app");
                 // The gesture is returning to the pausing-task(s) rather than continuing with
                 // recents, so end the transition by moving the app back to the top (and also
@@ -1048,6 +1056,18 @@
             }
         }
 
+        private boolean allAppsAreTranslucent(ArrayList<TaskState> tasks) {
+            if (tasks == null || tasks.isEmpty()) {
+                return false;
+            }
+            for (int i = tasks.size() - 1; i >= 0; --i) {
+                if (!tasks.get(i).mIsTranslucent) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         private void cleanUpPausingOrClosingTask(TaskState task, WindowContainerTransaction wct,
                 SurfaceControl.Transaction finishTransaction, boolean sendUserLeaveHint) {
             if (!sendUserLeaveHint && task.isLeaf()) {
@@ -1118,6 +1138,9 @@
         /** The surface/leash of the task provided by Core. */
         SurfaceControl mTaskSurface;
 
+        /** True when the task is translucent.  */
+        final boolean mIsTranslucent;
+
         /** The (local) animation-leash created for this task. Only non-null for leafs. */
         @Nullable
         SurfaceControl mLeash;
@@ -1126,6 +1149,7 @@
             mToken = change.getContainer();
             mTaskInfo = change.getTaskInfo();
             mTaskSurface = change.getLeash();
+            mIsTranslucent = (change.getFlags() & FLAG_TRANSLUCENT) != 0;
             mLeash = leash;
         }
 
diff --git a/location/api/current.txt b/location/api/current.txt
index 5ed8c3c..85e9f65 100644
--- a/location/api/current.txt
+++ b/location/api/current.txt
@@ -88,12 +88,12 @@
   public final class Geocoder {
     ctor public Geocoder(@NonNull android.content.Context);
     ctor public Geocoder(@NonNull android.content.Context, @NonNull java.util.Locale);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int) throws java.io.IOException;
-    method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int) throws java.io.IOException;
-    method public void getFromLocationName(@NonNull String, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
-    method public void getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange(from=1) int) throws java.io.IOException;
+    method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange(from=1) int, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange(from=1) int) throws java.io.IOException;
+    method public void getFromLocationName(@NonNull String, @IntRange(from=1) int, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange(from=1) int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
+    method public void getFromLocationName(@NonNull String, @IntRange(from=1) int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
     method public static boolean isPresent();
   }
 
diff --git a/location/api/system-current.txt b/location/api/system-current.txt
index b1cf96d..2e7a541 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -591,6 +591,36 @@
 
 package android.location.provider {
 
+  @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public final class ForwardGeocodeRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getCallingAttributionTag();
+    method @NonNull public String getCallingPackage();
+    method public int getCallingUid();
+    method @NonNull public java.util.Locale getLocale();
+    method @NonNull public String getLocationName();
+    method @FloatRange(from=-90.0, to=90.0) public double getLowerLeftLatitude();
+    method @FloatRange(from=-180.0, to=180.0) public double getLowerLeftLongitude();
+    method @IntRange(from=1) public int getMaxResults();
+    method @FloatRange(from=-90.0, to=90.0) public double getUpperRightLatitude();
+    method @FloatRange(from=-180.0, to=180.0) public double getUpperRightLongitude();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ForwardGeocodeRequest> CREATOR;
+  }
+
+  public static final class ForwardGeocodeRequest.Builder {
+    ctor public ForwardGeocodeRequest.Builder(@NonNull String, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange(from=1) int, @NonNull java.util.Locale, int, @NonNull String);
+    method @NonNull public android.location.provider.ForwardGeocodeRequest build();
+    method @NonNull public android.location.provider.ForwardGeocodeRequest.Builder setCallingAttributionTag(@NonNull String);
+  }
+
+  @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public abstract class GeocodeProviderBase {
+    ctor public GeocodeProviderBase(@NonNull android.content.Context, @NonNull String);
+    method @NonNull public final android.os.IBinder getBinder();
+    method public abstract void onForwardGeocode(@NonNull android.location.provider.ForwardGeocodeRequest, @NonNull android.os.OutcomeReceiver<java.util.List<android.location.Address>,java.lang.Exception>);
+    method public abstract void onReverseGeocode(@NonNull android.location.provider.ReverseGeocodeRequest, @NonNull android.os.OutcomeReceiver<java.util.List<android.location.Address>,java.lang.Exception>);
+    field public static final String ACTION_GEOCODE_PROVIDER = "com.android.location.service.GeocodeProvider";
+  }
+
   public abstract class LocationProviderBase {
     ctor public LocationProviderBase(@NonNull android.content.Context, @NonNull String, @NonNull android.location.provider.ProviderProperties);
     method @Nullable public final android.os.IBinder getBinder();
@@ -642,5 +672,24 @@
     method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
   }
 
+  @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public final class ReverseGeocodeRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getCallingAttributionTag();
+    method @NonNull public String getCallingPackage();
+    method public int getCallingUid();
+    method @FloatRange(from=-90.0, to=90.0) public double getLatitude();
+    method @NonNull public java.util.Locale getLocale();
+    method @FloatRange(from=-180.0, to=180.0) public double getLongitude();
+    method @IntRange(from=1) public int getMaxResults();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ReverseGeocodeRequest> CREATOR;
+  }
+
+  public static final class ReverseGeocodeRequest.Builder {
+    ctor public ReverseGeocodeRequest.Builder(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange(from=0) int, @NonNull java.util.Locale, int, @NonNull String);
+    method @NonNull public android.location.provider.ReverseGeocodeRequest build();
+    method @NonNull public android.location.provider.ReverseGeocodeRequest.Builder setCallingAttributionTag(@NonNull String);
+  }
+
 }
 
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index a158344..cdde7c6 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -21,11 +21,13 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.IGeocodeCallback;
+import android.location.provider.ReverseGeocodeRequest;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 
-import com.android.internal.util.Preconditions;
-
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
@@ -33,6 +35,7 @@
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * A class for handling geocoding and reverse geocoding. Geocoding is the process of transforming a
@@ -42,9 +45,12 @@
  * example one might contain the full street address of the closest building, while another might
  * contain only a city name and postal code.
  *
- * The Geocoder class requires a backend service that is not included in the core android framework.
- * The Geocoder query methods will return an empty list if there no backend service in the platform.
- * Use the isPresent() method to determine whether a Geocoder implementation exists.
+ * <p>Use the isPresent() method to determine whether a Geocoder implementation exists on the
+ * current device. If no implementation is present, any attempt to geocode will result in an error.
+ *
+ * <p>Geocoder implementations are only required to make a best effort to return results in the
+ * chosen locale. Note that geocoder implementations may return results in other locales if they
+ * have no information available for the chosen locale.
  *
  * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
  * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful or
@@ -52,45 +58,53 @@
  */
 public final class Geocoder {
 
-    /** A listener for asynchronous geocoding results. */
+    /**
+     * A listener for asynchronous geocoding results. Only one of the methods will ever be invoked
+     * per geocoding attempt. There are no guarantees on how long it will take for a method to be
+     * invoked, nor any guarantees on the format or availability of error information.
+     */
     public interface GeocodeListener {
         /** Invoked when geocoding completes successfully. May return an empty list. */
         void onGeocode(@NonNull List<Address> addresses);
-        /** Invoked when geocoding fails, with a brief error message. */
+
+        /** Invoked when geocoding fails, with an optional error message. */
         default void onError(@Nullable String errorMessage) {}
     }
 
-    private static final long TIMEOUT_MS = 60000;
+    private static final long TIMEOUT_MS = 15000;
 
-    private final GeocoderParams mParams;
+    private final Context mContext;
+    private final Locale mLocale;
     private final ILocationManager mService;
 
     /**
-     * Returns true if there is a geocoder implementation present that may return results. If true,
-     * there is still no guarantee that any individual geocoding attempt will succeed.
+     * Returns true if there is a geocoder implementation present on the device that may return
+     * results. If true, there is still no guarantee that any individual geocoding attempt will
+     * succeed.
      */
     public static boolean isPresent() {
         ILocationManager lm = Objects.requireNonNull(ILocationManager.Stub.asInterface(
                 ServiceManager.getService(Context.LOCATION_SERVICE)));
         try {
-            return lm.geocoderIsPresent();
+            return lm.isGeocodeAvailable();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * Constructs a Geocoder localized for the default locale.
-     */
+    /** Constructs a Geocoder localized for {@link Locale#getDefault()}. */
     public Geocoder(@NonNull Context context) {
         this(context, Locale.getDefault());
     }
 
     /**
-     * Constructs a Geocoder localized for the given locale.
+     * Constructs a Geocoder localized for the given locale. Note that geocoder implementations will
+     * only make a best effort to return results in the given locale, and there is no guarantee that
+     * returned results will be in the specific locale.
      */
     public Geocoder(@NonNull Context context, @NonNull Locale locale) {
-        mParams = new GeocoderParams(context, locale);
+        mContext = Objects.requireNonNull(context);
+        mLocale = Objects.requireNonNull(locale);
         mService = ILocationManager.Stub.asInterface(
                 ServiceManager.getService(Context.LOCATION_SERVICE));
     }
@@ -103,31 +117,28 @@
      * <p class="warning"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.</p>
+     * purposes.
      *
      * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
-     * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
-     * asynchronous version of this API. If that is not possible, this should be run on a background
-     * thread to avoid blocking other operations.</p>
+     * excessive amounts of time. It's strongly encouraged to use the asynchronous version of this
+     * API. If that is not possible, this should be run on a background thread to avoid blocking
+     * other operations.
      *
      * @param latitude the latitude a point for the search
      * @param longitude the longitude a point for the search
      * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
-     *
-     * @return a list of Address objects. Returns null or empty list if no matches were
-     * found or there is no backend service available.
-     *
+     * @return a list of Address objects. Returns null or empty list if no matches were found or
+     *     there is no backend service available.
      * @throws IllegalArgumentException if latitude or longitude is invalid
      * @throws IOException if there is a failure
-     *
      * @deprecated Use {@link #getFromLocation(double, double, int, GeocodeListener)} instead to
-     * avoid blocking a thread waiting for results.
+     *     avoid blocking a thread waiting for results.
      */
     @Deprecated
     public @Nullable List<Address> getFromLocation(
             @FloatRange(from = -90D, to = 90D) double latitude,
-            @FloatRange(from = -180D, to = 180D)double longitude,
-            @IntRange int maxResults)
+            @FloatRange(from = -180D, to = 180D) double longitude,
+            @IntRange(from = 1) int maxResults)
             throws IOException {
         SynchronousGeocoder listener = new SynchronousGeocoder();
         getFromLocation(latitude, longitude, maxResults, listener);
@@ -142,26 +153,32 @@
      * <p class="warning"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.</p>
+     * purposes.
      *
      * @param latitude the latitude a point for the search
      * @param longitude the longitude a point for the search
      * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
      * @param listener a listener for receiving results
-     *
      * @throws IllegalArgumentException if latitude or longitude is invalid
      */
     public void getFromLocation(
             @FloatRange(from = -90D, to = 90D) double latitude,
             @FloatRange(from = -180D, to = 180D) double longitude,
-            @IntRange int maxResults,
+            @IntRange(from = 1) int maxResults,
             @NonNull GeocodeListener listener) {
-        Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude");
-        Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude");
-
+        ReverseGeocodeRequest.Builder b =
+                new ReverseGeocodeRequest.Builder(
+                        latitude,
+                        longitude,
+                        maxResults,
+                        mLocale,
+                        Process.myUid(),
+                        mContext.getPackageName());
+        if (mContext.getAttributionTag() != null) {
+            b.setCallingAttributionTag(mContext.getAttributionTag());
+        }
         try {
-            mService.getFromLocation(latitude, longitude, maxResults, mParams,
-                    new GeocoderImpl(listener));
+            mService.reverseGeocode(b.build(), new GeocodeCallbackImpl(listener));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -176,29 +193,25 @@
      * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.</p>
+     * purposes.
      *
      * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
-     * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
-     * asynchronous version of this API. If that is not possible, this should be run on a background
-     * thread to avoid blocking other operations.</p>
+     * excessive amounts of time. It's strongly encouraged to use the asynchronous version of this
+     * API. If that is not possible, this should be run on a background thread to avoid blocking
+     * other operations.
      *
      * @param locationName a user-supplied description of a location
      * @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended
-     *
-     * @return a list of Address objects. Returns null or empty list if no matches were
-     * found or there is no backend service available.
-     *
+     * @return a list of Address objects. Returns null or empty list if no matches were found or
+     *     there is no backend service available.
      * @throws IllegalArgumentException if locationName is null
      * @throws IOException if there is a failure
-     *
      * @deprecated Use {@link #getFromLocationName(String, int, GeocodeListener)} instead to avoid
-     * blocking a thread waiting for results.
+     *     blocking a thread waiting for results.
      */
     @Deprecated
     public @Nullable List<Address> getFromLocationName(
-            @NonNull String locationName,
-            @IntRange int maxResults) throws IOException {
+            @NonNull String locationName, @IntRange(from = 1) int maxResults) throws IOException {
         return getFromLocationName(locationName, maxResults, 0, 0, 0, 0);
     }
 
@@ -211,17 +224,16 @@
      * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.</p>
+     * purposes.
      *
      * @param locationName a user-supplied description of a location
      * @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended
      * @param listener a listener for receiving results
-     *
      * @throws IllegalArgumentException if locationName is null
      */
     public void getFromLocationName(
             @NonNull String locationName,
-            @IntRange int maxResults,
+            @IntRange(from = 1) int maxResults,
             @NonNull GeocodeListener listener) {
         getFromLocationName(locationName, maxResults, 0, 0, 0, 0, listener);
     }
@@ -232,45 +244,42 @@
      * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
      * localized for the locale provided to this class's constructor.
      *
-     * <p> You may specify a bounding box for the search results by including the latitude and
+     * <p>You may specify a bounding box for the search results by including the latitude and
      * longitude of the lower left point and upper right point of the box.
      *
      * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.</p>
+     * purposes.
      *
      * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
-     * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
-     * asynchronous version of this API. If that is not possible, this should be run on a background
-     * thread to avoid blocking other operations.</p>
+     * excessive amounts of time. It's strongly encouraged to use the asynchronous version of this
+     * API. If that is not possible, this should be run on a background thread to avoid blocking
+     * other operations.
      *
-     * @param locationName        a user-supplied description of a location
-     * @param maxResults          max number of addresses to return. Smaller numbers (1 to 5) are
-     *                            recommended
-     * @param lowerLeftLatitude   the latitude of the lower left corner of the bounding box
-     * @param lowerLeftLongitude  the longitude of the lower left corner of the bounding box
-     * @param upperRightLatitude  the latitude of the upper right corner of the bounding box
+     * @param locationName a user-supplied description of a location
+     * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
+     * @param lowerLeftLatitude the latitude of the lower left corner of the bounding box
+     * @param lowerLeftLongitude the longitude of the lower left corner of the bounding box
+     * @param upperRightLatitude the latitude of the upper right corner of the bounding box
      * @param upperRightLongitude the longitude of the upper right corner of the bounding box
-     *
-     * @return a list of Address objects. Returns null or empty list if no matches were
-     * found or there is no backend service available.
-     *
+     * @return a list of Address objects. Returns null or empty list if no matches were found or
+     *     there is no backend service available.
      * @throws IllegalArgumentException if locationName is null
      * @throws IllegalArgumentException if any latitude or longitude is invalid
-     * @throws IOException              if there is a failure
-     *
+     * @throws IOException if there is a failure
      * @deprecated Use {@link #getFromLocationName(String, int, double, double, double, double,
-     * GeocodeListener)} instead to avoid blocking a thread waiting for results.
+     *     GeocodeListener)} instead to avoid blocking a thread waiting for results.
      */
     @Deprecated
     public @Nullable List<Address> getFromLocationName(
             @NonNull String locationName,
-            @IntRange int maxResults,
+            @IntRange(from = 1) int maxResults,
             @FloatRange(from = -90D, to = 90D) double lowerLeftLatitude,
             @FloatRange(from = -180D, to = 180D) double lowerLeftLongitude,
             @FloatRange(from = -90D, to = 90D) double upperRightLatitude,
-            @FloatRange(from = -180D, to = 180D) double upperRightLongitude) throws IOException {
+            @FloatRange(from = -180D, to = 180D) double upperRightLongitude)
+            throws IOException {
         SynchronousGeocoder listener = new SynchronousGeocoder();
         getFromLocationName(locationName, maxResults, lowerLeftLatitude, lowerLeftLongitude,
                 upperRightLatitude, upperRightLongitude, listener);
@@ -283,75 +292,79 @@
      * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
      * localized for the locale provided to this class's constructor.
      *
-     * <p> You may specify a bounding box for the search results by including the latitude and
+     * <p>You may specify a bounding box for the search results by including the latitude and
      * longitude of the lower left point and upper right point of the box.
      *
      * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.</p>
+     * purposes.
      *
-     * @param locationName        a user-supplied description of a location
-     * @param maxResults          max number of addresses to return. Smaller numbers (1 to 5) are
-     *                            recommended
-     * @param lowerLeftLatitude   the latitude of the lower left corner of the bounding box
-     * @param lowerLeftLongitude  the longitude of the lower left corner of the bounding box
-     * @param upperRightLatitude  the latitude of the upper right corner of the bounding box
+     * @param locationName a user-supplied description of a location
+     * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
+     * @param lowerLeftLatitude the latitude of the lower left corner of the bounding box
+     * @param lowerLeftLongitude the longitude of the lower left corner of the bounding box
+     * @param upperRightLatitude the latitude of the upper right corner of the bounding box
      * @param upperRightLongitude the longitude of the upper right corner of the bounding box
-     * @param listener            a listener for receiving results
-     *
+     * @param listener a listener for receiving results
      * @throws IllegalArgumentException if locationName is null
      * @throws IllegalArgumentException if any latitude or longitude is invalid
      */
     public void getFromLocationName(
             @NonNull String locationName,
-            @IntRange int maxResults,
+            @IntRange(from = 1) int maxResults,
             @FloatRange(from = -90D, to = 90D) double lowerLeftLatitude,
             @FloatRange(from = -180D, to = 180D) double lowerLeftLongitude,
             @FloatRange(from = -90D, to = 90D) double upperRightLatitude,
             @FloatRange(from = -180D, to = 180D) double upperRightLongitude,
             @NonNull GeocodeListener listener) {
-        Preconditions.checkArgument(locationName != null);
-        Preconditions.checkArgumentInRange(lowerLeftLatitude, -90.0, 90.0, "lowerLeftLatitude");
-        Preconditions.checkArgumentInRange(lowerLeftLongitude, -180.0, 180.0, "lowerLeftLongitude");
-        Preconditions.checkArgumentInRange(upperRightLatitude, -90.0, 90.0, "upperRightLatitude");
-        Preconditions.checkArgumentInRange(upperRightLongitude, -180.0, 180.0,
-                "upperRightLongitude");
-
+        ForwardGeocodeRequest.Builder b =
+                new ForwardGeocodeRequest.Builder(
+                        locationName,
+                        lowerLeftLatitude,
+                        lowerLeftLongitude,
+                        upperRightLatitude,
+                        upperRightLongitude,
+                        maxResults,
+                        mLocale,
+                        Process.myUid(),
+                        mContext.getPackageName());
+        if (mContext.getAttributionTag() != null) {
+            b.setCallingAttributionTag(mContext.getAttributionTag());
+        }
         try {
-            mService.getFromLocationName(locationName, lowerLeftLatitude, lowerLeftLongitude,
-                    upperRightLatitude, upperRightLongitude, maxResults, mParams,
-                    new GeocoderImpl(listener));
+            mService.forwardGeocode(b.build(), new GeocodeCallbackImpl(listener));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
-    private static class GeocoderImpl extends IGeocodeListener.Stub {
+    private static class GeocodeCallbackImpl extends IGeocodeCallback.Stub {
 
-        private GeocodeListener mListener;
+        @Nullable private GeocodeListener mListener;
 
-        GeocoderImpl(GeocodeListener listener) {
+        GeocodeCallbackImpl(GeocodeListener listener) {
             mListener = Objects.requireNonNull(listener);
         }
 
         @Override
-        public void onResults(String error, List<Address> addresses) throws RemoteException {
+        public void onError(@Nullable String error) {
             if (mListener == null) {
                 return;
             }
 
-            GeocodeListener listener = mListener;
+            mListener.onError(error);
             mListener = null;
+        }
 
-            if (error != null) {
-                listener.onError(error);
-            } else {
-                if (addresses == null) {
-                    addresses = Collections.emptyList();
-                }
-                listener.onGeocode(addresses);
+        @Override
+        public void onResults(List<Address> addresses) {
+            if (mListener == null) {
+                return;
             }
+
+            mListener.onGeocode(addresses);
+            mListener = null;
         }
     }
 
@@ -364,21 +377,21 @@
         SynchronousGeocoder() {}
 
         @Override
-        public void onGeocode(List<Address> addresses) {
+        public void onGeocode(@NonNull List<Address> addresses) {
             mResults = addresses;
             mLatch.countDown();
         }
 
         @Override
-        public void onError(String errorMessage) {
-            mError = errorMessage;
+        public void onError(@Nullable String error) {
+            mError = error;
             mLatch.countDown();
         }
 
         public List<Address> getResults() throws IOException {
             try {
                 if (!mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                    mError = "Service not Available";
+                    throw new IOException(new TimeoutException());
                 }
             } catch (InterruptedException e) {
                 Thread.currentThread().interrupt();
diff --git a/location/java/android/location/IGeocodeProvider.aidl b/location/java/android/location/IGeocodeProvider.aidl
deleted file mode 100644
index e661ca6..0000000
--- a/location/java/android/location/IGeocodeProvider.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2009 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.location;
-
-import android.location.Address;
-import android.location.IGeocodeListener;
-import android.location.GeocoderParams;
-
-/**
- * An interface for location providers implementing the Geocoder services.
- *
- * {@hide}
- */
-interface IGeocodeProvider {
-
-    oneway void getFromLocation(double latitude, double longitude, int maxResults, in GeocoderParams params, in IGeocodeListener listener);
-    oneway void getFromLocationName(String locationName, double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude,
-        double upperRightLongitude, int maxResults, in GeocoderParams params, in IGeocodeListener listener);
-}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 72761ef..c96c118 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -19,13 +19,11 @@
 import android.app.PendingIntent;
 import android.location.Address;
 import android.location.Criteria;
-import android.location.GeocoderParams;
 import android.location.Geofence;
 import android.location.GnssAntennaInfo;
 import android.location.GnssCapabilities;
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementRequest;
-import android.location.IGeocodeListener;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssStatusListener;
@@ -37,8 +35,11 @@
 import android.location.Location;
 import android.location.LocationRequest;
 import android.location.LocationTime;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.IGeocodeCallback;
 import android.location.provider.IProviderRequestListener;
 import android.location.provider.ProviderProperties;
+import android.location.provider.ReverseGeocodeRequest;
 import android.os.Bundle;
 import android.os.ICancellationSignal;
 import android.os.PackageTagsList;
@@ -68,13 +69,9 @@
     void requestGeofence(in Geofence geofence, in PendingIntent intent, String packageName, String attributionTag);
     void removeGeofence(in PendingIntent intent);
 
-    boolean geocoderIsPresent();
-    void getFromLocation(double latitude, double longitude, int maxResults,
-        in GeocoderParams params, in IGeocodeListener listener);
-    void getFromLocationName(String locationName,
-        double lowerLeftLatitude, double lowerLeftLongitude,
-        double upperRightLatitude, double upperRightLongitude, int maxResults,
-        in GeocoderParams params, in IGeocodeListener listener);
+    boolean isGeocodeAvailable();
+    void reverseGeocode(in ReverseGeocodeRequest request, in IGeocodeCallback callback);
+    void forwardGeocode(in ForwardGeocodeRequest request, in IGeocodeCallback callback);
 
     GnssCapabilities getGnssCapabilities();
     int getGnssYearOfHardware();
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index 0fa641b..156be38 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -1,6 +1,13 @@
 package: "android.location.flags"
 
 flag {
+    name: "new_geocoder"
+    namespace: "location"
+    description: "Flag for new Geocoder APIs"
+    bug: "229872126"
+}
+
+flag {
     name: "location_bypass"
     namespace: "location"
     description: "Enable location bypass appops behavior"
diff --git a/location/java/android/location/GeocoderParams.aidl b/location/java/android/location/provider/ForwardGeocodeRequest.aidl
similarity index 74%
copy from location/java/android/location/GeocoderParams.aidl
copy to location/java/android/location/provider/ForwardGeocodeRequest.aidl
index 2484e20..acd6190 100644
--- a/location/java/android/location/GeocoderParams.aidl
+++ b/location/java/android/location/provider/ForwardGeocodeRequest.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2010, The Android Open Source Project
+ * 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
+ *      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,
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.location;
+package android.location.provider;
 
-parcelable GeocoderParams;
+parcelable ForwardGeocodeRequest;
diff --git a/location/java/android/location/provider/ForwardGeocodeRequest.java b/location/java/android/location/provider/ForwardGeocodeRequest.java
new file mode 100644
index 0000000..8f227b1
--- /dev/null
+++ b/location/java/android/location/provider/ForwardGeocodeRequest.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright 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.location.provider;
+
+import static java.lang.Math.max;
+
+import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.location.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Forward geocode (ie from address to lat/lng) provider request.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NEW_GEOCODER)
+@SystemApi
+public final class ForwardGeocodeRequest implements Parcelable {
+
+    private final String mLocationName;
+    private final double mLowerLeftLatitude;
+    private final double mLowerLeftLongitude;
+    private final double mUpperRightLatitude;
+    private final double mUpperRightLongitude;
+    private final int mMaxResults;
+    private final Locale mLocale;
+    private final int mCallingUid;
+    private final String mCallingPackage;
+    @Nullable private final String mCallingAttributionTag;
+
+    private ForwardGeocodeRequest(
+            @NonNull String locationName,
+            double lowerLeftLatitude,
+            double lowerLeftLongitude,
+            double upperRightLatitude,
+            double upperRightLongitude,
+            int maxResults,
+            @NonNull Locale locale,
+            int callingUid,
+            @NonNull String callingPackage,
+            @Nullable String callingAttributionTag) {
+        Preconditions.checkArgument(locationName != null, "locationName must not be null");
+        Preconditions.checkArgumentInRange(lowerLeftLatitude, -90.0, 90.0, "lowerLeftLatitude");
+        Preconditions.checkArgumentInRange(lowerLeftLongitude, -180.0, 180.0, "lowerLeftLongitude");
+        Preconditions.checkArgumentInRange(upperRightLatitude, -90.0, 90.0, "upperRightLatitude");
+        Preconditions.checkArgumentInRange(
+                upperRightLongitude, -180.0, 180.0, "upperRightLongitude");
+
+        mLocationName = locationName;
+        mLowerLeftLatitude = lowerLeftLatitude;
+        mLowerLeftLongitude = lowerLeftLongitude;
+        mUpperRightLatitude = upperRightLatitude;
+        mUpperRightLongitude = upperRightLongitude;
+        mMaxResults = max(maxResults, 1);
+        mLocale = Objects.requireNonNull(locale);
+
+        mCallingUid = callingUid;
+        mCallingPackage = Objects.requireNonNull(callingPackage);
+        mCallingAttributionTag = callingAttributionTag;
+    }
+
+    /**
+     * The location name to be forward geocoded. An arbitrary user string that could have any value.
+     */
+    @NonNull
+    public String getLocationName() {
+        return mLocationName;
+    }
+
+    /** The lower left latitude of the bounding box that should constrain forward geocoding. */
+    @FloatRange(from = -90.0, to = 90.0)
+    public double getLowerLeftLatitude() {
+        return mLowerLeftLatitude;
+    }
+
+    /** The lower left longitude of the bounding box that should constrain forward geocoding. */
+    @FloatRange(from = -180.0, to = 180.0)
+    public double getLowerLeftLongitude() {
+        return mLowerLeftLongitude;
+    }
+
+    /** The upper right latitude of the bounding box that should constrain forward geocoding. */
+    @FloatRange(from = -90.0, to = 90.0)
+    public double getUpperRightLatitude() {
+        return mUpperRightLatitude;
+    }
+
+    /** The upper right longitude of the bounding box that should constrain forward geocoding. */
+    @FloatRange(from = -180.0, to = 180.0)
+    public double getUpperRightLongitude() {
+        return mUpperRightLongitude;
+    }
+
+    /** The maximum number of forward geocoding results that should be returned. */
+    @IntRange(from = 1)
+    public int getMaxResults() {
+        return mMaxResults;
+    }
+
+    /** The locale that results should be localized to (best effort). */
+    @NonNull
+    public Locale getLocale() {
+        return mLocale;
+    }
+
+    /** The UID of the caller this geocoding request is happening on behalf of. */
+    public int getCallingUid() {
+        return mCallingUid;
+    }
+
+    /** The package of the caller this geocoding request is happening on behalf of. */
+    @NonNull
+    public String getCallingPackage() {
+        return mCallingPackage;
+    }
+
+    /** The attribution tag of the caller this geocoding request is happening on behalf of. */
+    @Nullable
+    public String getCallingAttributionTag() {
+        return mCallingAttributionTag;
+    }
+
+    public static final @NonNull Creator<ForwardGeocodeRequest> CREATOR =
+            new Creator<>() {
+                @Override
+                public ForwardGeocodeRequest createFromParcel(Parcel in) {
+                    return new ForwardGeocodeRequest(
+                            Objects.requireNonNull(in.readString8()),
+                            in.readDouble(),
+                            in.readDouble(),
+                            in.readDouble(),
+                            in.readDouble(),
+                            in.readInt(),
+                            new Locale(in.readString8(), in.readString8(), in.readString8()),
+                            in.readInt(),
+                            Objects.requireNonNull(in.readString8()),
+                            in.readString8());
+                }
+
+                @Override
+                public ForwardGeocodeRequest[] newArray(int size) {
+                    return new ForwardGeocodeRequest[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeString8(mLocationName);
+        parcel.writeDouble(mLowerLeftLatitude);
+        parcel.writeDouble(mLowerLeftLongitude);
+        parcel.writeDouble(mUpperRightLatitude);
+        parcel.writeDouble(mUpperRightLongitude);
+        parcel.writeInt(mMaxResults);
+        parcel.writeString8(mLocale.getLanguage());
+        parcel.writeString8(mLocale.getCountry());
+        parcel.writeString8(mLocale.getVariant());
+        parcel.writeInt(mCallingUid);
+        parcel.writeString8(mCallingPackage);
+        parcel.writeString8(mCallingAttributionTag);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object object) {
+        if (object instanceof ForwardGeocodeRequest that) {
+            return mLowerLeftLatitude == that.mLowerLeftLatitude
+                    && mLowerLeftLongitude == that.mLowerLeftLongitude
+                    && mUpperRightLatitude == that.mUpperRightLatitude
+                    && mUpperRightLongitude == that.mUpperRightLongitude
+                    && mMaxResults == that.mMaxResults
+                    && mCallingUid == that.mCallingUid
+                    && mLocale.equals(that.mLocale)
+                    && mCallingPackage.equals(that.mCallingPackage)
+                    && mLocationName.equals(that.mLocationName)
+                    && Objects.equals(mCallingAttributionTag, that.mCallingAttributionTag);
+        }
+
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mLocationName,
+                mLowerLeftLatitude,
+                mLowerLeftLongitude,
+                mUpperRightLatitude,
+                mUpperRightLongitude,
+                mMaxResults,
+                mLocale,
+                mCallingUid,
+                mCallingPackage,
+                mCallingAttributionTag);
+    }
+
+    /** A Builder for {@link ReverseGeocodeRequest}s. */
+    public static final class Builder {
+
+        private final String mLocationName;
+        private final double mLowerLeftLatitude;
+        private final double mLowerLeftLongitude;
+        private final double mUpperRightLatitude;
+        private final double mUpperRightLongitude;
+        private final int mMaxResults;
+        private final Locale mLocale;
+
+        private final int mCallingUid;
+        private final String mCallingPackage;
+        @Nullable private String mCallingAttributionTag;
+
+        /** Creates a new Builder instance with the given parameters. */
+        public Builder(
+                @NonNull String locationName,
+                @FloatRange(from = -90.0, to = 90.0) double lowerLeftLatitude,
+                @FloatRange(from = -180.0, to = 180.0) double lowerLeftLongitude,
+                @FloatRange(from = -90.0, to = 90.0) double upperRightLatitude,
+                @FloatRange(from = -180.0, to = 180.0) double upperRightLongitude,
+                @IntRange(from = 1) int maxResults,
+                @NonNull Locale locale,
+                int callingUid,
+                @NonNull String callingPackage) {
+            mLocationName = locationName;
+            mLowerLeftLatitude = lowerLeftLatitude;
+            mLowerLeftLongitude = lowerLeftLongitude;
+            mUpperRightLatitude = upperRightLatitude;
+            mUpperRightLongitude = upperRightLongitude;
+            mMaxResults = maxResults;
+            mLocale = locale;
+            mCallingUid = callingUid;
+            mCallingPackage = callingPackage;
+            mCallingAttributionTag = null;
+        }
+
+        /** Sets the attribution tag. */
+        @NonNull
+        public Builder setCallingAttributionTag(@NonNull String attributionTag) {
+            mCallingAttributionTag = attributionTag;
+            return this;
+        }
+
+        /** Builds a {@link ForwardGeocodeRequest}. */
+        @NonNull
+        public ForwardGeocodeRequest build() {
+            return new ForwardGeocodeRequest(
+                    mLocationName,
+                    mLowerLeftLatitude,
+                    mLowerLeftLongitude,
+                    mUpperRightLatitude,
+                    mUpperRightLongitude,
+                    mMaxResults,
+                    mLocale,
+                    mCallingUid,
+                    mCallingPackage,
+                    mCallingAttributionTag);
+        }
+    }
+}
diff --git a/location/java/android/location/provider/GeocodeProviderBase.java b/location/java/android/location/provider/GeocodeProviderBase.java
new file mode 100644
index 0000000..e2c48b9
--- /dev/null
+++ b/location/java/android/location/provider/GeocodeProviderBase.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location.provider;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Address;
+import android.location.flags.Flags;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.OutcomeReceiver;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Base class for geocode providers outside the system server.
+ *
+ * <p>Geocode providers should be wrapped in a non-exported service which returns the result of
+ * {@link #getBinder()} from the service's {@link android.app.Service#onBind(Intent)} method. The
+ * service should not be exported so that components other than the system server cannot bind to it.
+ * Alternatively, the service may be guarded by a permission that only system server can obtain. The
+ * service may specify metadata on its capabilities:
+ *
+ * <ul>
+ *   <li>"serviceVersion": An integer version code to help tie break if multiple services are
+ *       capable of implementing the geocode provider. All else equal, the service with the highest
+ *       version code will be chosen. Assumed to be 0 if not specified.
+ *   <li>"serviceIsMultiuser": A boolean property, indicating if the service wishes to take
+ *       responsibility for handling changes to the current user on the device. If true, the service
+ *       will always be bound from the system user. If false, the service will always be bound from
+ *       the current user. If the current user changes, the old binding will be released, and a new
+ *       binding established under the new user. Assumed to be false if not specified.
+ * </ul>
+ *
+ * <p>The service should have an intent filter in place for the geocode provider as specified by the
+ * constant in this class.
+ *
+ * <p>Geocode providers are identified by their UID / package name / attribution tag. Based on this
+ * identity, geocode providers may be given some special privileges.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NEW_GEOCODER)
+@SystemApi
+public abstract class GeocodeProviderBase {
+
+    /**
+     * The action the wrapping service should have in its intent filter to implement the geocode
+     * provider.
+     */
+    @SuppressLint("ActionValue")
+    public static final String ACTION_GEOCODE_PROVIDER =
+            "com.android.location.service.GeocodeProvider";
+
+    final String mTag;
+    @Nullable final String mAttributionTag;
+    final IBinder mBinder;
+
+    /**
+     * Subclasses should pass in a context and an arbitrary tag that may be used for logcat logging
+     * of errors, and thus should uniquely identify the class.
+     */
+    public GeocodeProviderBase(@NonNull Context context, @NonNull String tag) {
+        mTag = tag;
+        mAttributionTag = context.getAttributionTag();
+        mBinder = new Service();
+    }
+
+    /**
+     * Returns the IBinder instance that should be returned from the {@link
+     * android.app.Service#onBind(Intent)} method of the wrapping service.
+     */
+    @NonNull
+    public final IBinder getBinder() {
+        return mBinder;
+    }
+
+    /**
+     * Requests forward geocoding of the given arguments. The given callback must be invoked once.
+     */
+    public abstract void onForwardGeocode(
+            @NonNull ForwardGeocodeRequest request,
+            @NonNull OutcomeReceiver<List<Address>, Exception> callback);
+
+    /**
+     * Requests reverse geocoding of the given arguments. The given callback must be invoked once.
+     */
+    public abstract void onReverseGeocode(
+            @NonNull ReverseGeocodeRequest request,
+            @NonNull OutcomeReceiver<List<Address>, Exception> callback);
+
+    private class Service extends IGeocodeProvider.Stub {
+        @Override
+        public void forwardGeocode(ForwardGeocodeRequest request, IGeocodeCallback callback) {
+            try {
+                onForwardGeocode(request, new SingleUseCallback(callback));
+            } catch (RuntimeException e) {
+                // exceptions on one-way binder threads are dropped - move to a different thread
+                Log.w(mTag, e);
+                new Handler(Looper.getMainLooper())
+                        .post(
+                                () -> {
+                                    throw new AssertionError(e);
+                                });
+            }
+        }
+
+        @Override
+        public void reverseGeocode(ReverseGeocodeRequest request, IGeocodeCallback callback) {
+            try {
+                onReverseGeocode(request, new SingleUseCallback(callback));
+            } catch (RuntimeException e) {
+                // exceptions on one-way binder threads are dropped - move to a different thread
+                Log.w(mTag, e);
+                new Handler(Looper.getMainLooper())
+                        .post(
+                                () -> {
+                                    throw new AssertionError(e);
+                                });
+            }
+        }
+    }
+
+    private static class SingleUseCallback implements OutcomeReceiver<List<Address>, Exception> {
+
+        private final AtomicReference<IGeocodeCallback> mCallback;
+
+        SingleUseCallback(IGeocodeCallback callback) {
+            mCallback = new AtomicReference<>(callback);
+        }
+
+        @Override
+        public void onError(Exception e) {
+            try {
+                Objects.requireNonNull(mCallback.getAndSet(null)).onError(e.toString());
+            } catch (RemoteException r) {
+                throw r.rethrowFromSystemServer();
+            }
+        }
+
+        @Override
+        public void onResult(List<Address> results) {
+            try {
+                Objects.requireNonNull(mCallback.getAndSet(null)).onResults(results);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+}
diff --git a/location/java/android/location/IGeocodeListener.aidl b/location/java/android/location/provider/IGeocodeCallback.aidl
similarity index 76%
rename from location/java/android/location/IGeocodeListener.aidl
rename to location/java/android/location/provider/IGeocodeCallback.aidl
index 8e10411..cf52713 100644
--- a/location/java/android/location/IGeocodeListener.aidl
+++ b/location/java/android/location/provider/IGeocodeCallback.aidl
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-package android.location;
+package android.location.provider;
 
 import android.location.Address;
 
 /**
- * An interface for returning geocode results.
- *
- * {@hide}
+ * Binder interface for geocoding callbacks.
+ * @hide
  */
-interface IGeocodeListener {
-
-    oneway void onResults(String error, in List<Address> results);
+oneway interface IGeocodeCallback {
+    void onError(String error);
+    void onResults(in List<Address> results);
 }
diff --git a/location/java/android/location/provider/IGeocodeProvider.aidl b/location/java/android/location/provider/IGeocodeProvider.aidl
new file mode 100644
index 0000000..9217438
--- /dev/null
+++ b/location/java/android/location/provider/IGeocodeProvider.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2009 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.location.provider;
+
+import android.location.provider.IGeocodeCallback;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.ReverseGeocodeRequest;
+
+/**
+ * Binder interface for services that implement geocode providers. Do not implement this directly,
+ * extend {@link GeocodeProviderBase} instead.
+ * @hide
+ */
+oneway interface IGeocodeProvider {
+    void forwardGeocode(in ForwardGeocodeRequest request, in IGeocodeCallback callback);
+    void reverseGeocode(in ReverseGeocodeRequest request, in IGeocodeCallback callback);
+}
diff --git a/location/java/android/location/GeocoderParams.aidl b/location/java/android/location/provider/ReverseGeocodeRequest.aidl
similarity index 75%
rename from location/java/android/location/GeocoderParams.aidl
rename to location/java/android/location/provider/ReverseGeocodeRequest.aidl
index 2484e20..015757a 100644
--- a/location/java/android/location/GeocoderParams.aidl
+++ b/location/java/android/location/provider/ReverseGeocodeRequest.aidl
@@ -1,11 +1,10 @@
 /*
- * Copyright (C) 2010, The Android Open Source Project
- *
+ * Copyright (C) 2024
  * 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
+ *      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,
@@ -14,6 +13,6 @@
  * limitations under the License.
  */
 
-package android.location;
+package android.location.provider;
 
-parcelable GeocoderParams;
+parcelable ReverseGeocodeRequest;
diff --git a/location/java/android/location/provider/ReverseGeocodeRequest.java b/location/java/android/location/provider/ReverseGeocodeRequest.java
new file mode 100644
index 0000000..57c9047
--- /dev/null
+++ b/location/java/android/location/provider/ReverseGeocodeRequest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 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.location.provider;
+
+import static java.lang.Math.max;
+
+import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.location.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Reverse geocode (ie from lat/lng to address) provider request.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NEW_GEOCODER)
+@SystemApi
+public final class ReverseGeocodeRequest implements Parcelable {
+
+    private final double mLatitude;
+    private final double mLongitude;
+    private final int mMaxResults;
+    private final Locale mLocale;
+
+    private final int mCallingUid;
+    private final String mCallingPackage;
+    @Nullable private final String mCallingAttributionTag;
+
+    private ReverseGeocodeRequest(
+            double latitude,
+            double longitude,
+            int maxResults,
+            Locale locale,
+            int callingUid,
+            String callingPackage,
+            @Nullable String callingAttributionTag) {
+        Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude");
+        Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude");
+
+        mLatitude = latitude;
+        mLongitude = longitude;
+        mMaxResults = max(maxResults, 1);
+        mLocale = Objects.requireNonNull(locale);
+
+        mCallingUid = callingUid;
+        mCallingPackage = Objects.requireNonNull(callingPackage);
+        mCallingAttributionTag = callingAttributionTag;
+    }
+
+    /** The latitude of the point to be reverse geocoded. */
+    @FloatRange(from = -90.0, to = 90.0)
+    public double getLatitude() {
+        return mLatitude;
+    }
+
+    /** The longitude of the point to be reverse geocoded. */
+    @FloatRange(from = -180.0, to = 180.0)
+    public double getLongitude() {
+        return mLongitude;
+    }
+
+    /** The maximum number of reverse geocoding results that should be returned. */
+    @IntRange(from = 1)
+    public int getMaxResults() {
+        return mMaxResults;
+    }
+
+    /** The locale that results should be localized to (best effort). */
+    @NonNull
+    public Locale getLocale() {
+        return mLocale;
+    }
+
+    /** The UID of the caller this geocoding request is happening on behalf of. */
+    public int getCallingUid() {
+        return mCallingUid;
+    }
+
+    /** The package of the caller this geocoding request is happening on behalf of. */
+    @NonNull
+    public String getCallingPackage() {
+        return mCallingPackage;
+    }
+
+    /** The attribution tag of the caller this geocoding request is happening on behalf of. */
+    @Nullable
+    public String getCallingAttributionTag() {
+        return mCallingAttributionTag;
+    }
+
+    public static final @NonNull Creator<ReverseGeocodeRequest> CREATOR =
+            new Creator<>() {
+                @Override
+                public ReverseGeocodeRequest createFromParcel(Parcel in) {
+                    return new ReverseGeocodeRequest(
+                            in.readDouble(),
+                            in.readDouble(),
+                            in.readInt(),
+                            new Locale(in.readString8(), in.readString8(), in.readString8()),
+                            in.readInt(),
+                            Objects.requireNonNull(in.readString8()),
+                            in.readString8());
+                }
+
+                @Override
+                public ReverseGeocodeRequest[] newArray(int size) {
+                    return new ReverseGeocodeRequest[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeDouble(mLatitude);
+        parcel.writeDouble(mLongitude);
+        parcel.writeInt(mMaxResults);
+        parcel.writeString8(mLocale.getLanguage());
+        parcel.writeString8(mLocale.getCountry());
+        parcel.writeString8(mLocale.getVariant());
+        parcel.writeInt(mCallingUid);
+        parcel.writeString8(mCallingPackage);
+        parcel.writeString8(mCallingAttributionTag);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object object) {
+        if (object instanceof ReverseGeocodeRequest that) {
+            return mLatitude == that.mLatitude
+                    && mLongitude == that.mLongitude
+                    && mMaxResults == that.mMaxResults
+                    && mCallingUid == that.mCallingUid
+                    && mLocale.equals(that.mLocale)
+                    && mCallingPackage.equals(that.mCallingPackage)
+                    && Objects.equals(mCallingAttributionTag, that.mCallingAttributionTag);
+        }
+
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mLatitude,
+                mLongitude,
+                mMaxResults,
+                mLocale,
+                mCallingUid,
+                mCallingPackage,
+                mCallingAttributionTag);
+    }
+
+    /** A Builder for {@link ReverseGeocodeRequest}s. */
+    public static final class Builder {
+
+        private final double mLatitude;
+        private final double mLongitude;
+        private final int mMaxResults;
+        private final Locale mLocale;
+
+        private final int mCallingUid;
+        private final String mCallingPackage;
+        @Nullable private String mCallingAttributionTag;
+
+        /** Creates a new Builder instance with the given parameters. */
+        public Builder(
+                @FloatRange(from = -90.0, to = 90.0) double latitude,
+                @FloatRange(from = -180.0, to = 180.0) double longitude,
+                @IntRange(from = 0) int maxResults,
+                @NonNull Locale locale,
+                int callingUid,
+                @NonNull String callingPackage) {
+            mLatitude = latitude;
+            mLongitude = longitude;
+            mMaxResults = maxResults;
+            mLocale = locale;
+            mCallingUid = callingUid;
+            mCallingPackage = callingPackage;
+            mCallingAttributionTag = null;
+        }
+
+        /** Sets the attribution tag. */
+        @NonNull
+        public Builder setCallingAttributionTag(@NonNull String attributionTag) {
+            mCallingAttributionTag = attributionTag;
+            return this;
+        }
+
+        /** Builds a {@link ReverseGeocodeRequest}. */
+        @NonNull
+        public ReverseGeocodeRequest build() {
+            return new ReverseGeocodeRequest(
+                    mLatitude,
+                    mLongitude,
+                    mMaxResults,
+                    mLocale,
+                    mCallingUid,
+                    mCallingPackage,
+                    mCallingAttributionTag);
+        }
+    }
+}
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index c9be579..b10019a 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -30,6 +30,7 @@
         "androidx.annotation_annotation",
     ],
     api_packages: [
+        "android.location",
         "com.android.location.provider",
         "com.android.location.timezone.provider",
     ],
diff --git a/location/lib/README.txt b/location/lib/README.txt
index 400a7dd..ae51872 100644
--- a/location/lib/README.txt
+++ b/location/lib/README.txt
@@ -1,30 +1,12 @@
 This library (com.android.location.provider.jar) is a shared java library
-containing classes required by unbundled location providers.
+containing classes required by unbundled providers. The library was created
+as a way of exposing API classes outside of the public API before SystemApi
+was possible. Now that SystemApi exists, no new classes should ever be added
+to this library, and all classes in this library should eventually be
+deprecated and new SystemApi replacements offered.
 
---- Rules of this library ---
-o This library is effectively a PUBLIC API for unbundled location providers
-  that may be distributed outside the system image. So it MUST BE API STABLE.
-  You can add but not remove. The rules are the same as for the
-  public platform SDK API.
-o This library can see and instantiate internal platform classes (such as
-  ProviderRequest.java), but it must not expose them in any public method
-  (or by extending them via inheritance). This would break clients of the
-  library because they cannot see the internal platform classes.
-
-This library is distributed in the system image, and loaded as
-a shared library. So you can change the implementation, but not
-the interface. In this way it is like framework.jar.
-
---- Why does this library exists? ---
-
-Unbundled location providers (such as the NetworkLocationProvider)
-can not use internal platform classes.
-
-So ideally all of these classes would be part of the public platform SDK API,
-but that doesn't seem like a great idea when only applications with a special
-signature can implement this API.
-
-The compromise is this library.
-
-It wraps internal platform classes (like ProviderRequest) with a stable
-API that does not leak the internal classes.
+Whether or not classes in this library can ever be removed must be answered on
+a case by case basis. Most of the classes are usually referenced by Google Play
+services (in which case references can be removed from that code base), but
+these classes may also be referenced by OEM code, which must be considered
+before any removal.
diff --git a/location/lib/api/system-current.txt b/location/lib/api/system-current.txt
index 7046abd..75e6bb4 100644
--- a/location/lib/api/system-current.txt
+++ b/location/lib/api/system-current.txt
@@ -1,4 +1,21 @@
 // Signature format: 2.0
+package android.location {
+
+  @Deprecated public class GeocoderParams implements android.os.Parcelable {
+    ctor @Deprecated public GeocoderParams(android.content.Context);
+    ctor @Deprecated public GeocoderParams(android.content.Context, java.util.Locale);
+    ctor @Deprecated public GeocoderParams(int, String, @Nullable String, java.util.Locale);
+    method @Deprecated public int describeContents();
+    method @Deprecated @Nullable public String getClientAttributionTag();
+    method @Deprecated @NonNull public String getClientPackage();
+    method @Deprecated public int getClientUid();
+    method @Deprecated @NonNull public java.util.Locale getLocale();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GeocoderParams> CREATOR;
+  }
+
+}
+
 package com.android.location.provider {
 
   @Deprecated public final class FusedLocationHardware {
@@ -25,6 +42,13 @@
     method @Deprecated public void onStatusChanged(int);
   }
 
+  @Deprecated public abstract class GeocodeProvider {
+    ctor @Deprecated public GeocodeProvider();
+    method @Deprecated public android.os.IBinder getBinder();
+    method @Deprecated public abstract String onGetFromLocation(double, double, int, android.location.GeocoderParams, java.util.List<android.location.Address>);
+    method @Deprecated public abstract String onGetFromLocationName(String, double, double, double, double, int, android.location.GeocoderParams, java.util.List<android.location.Address>);
+  }
+
   @Deprecated public class GmsFusedBatchOptions {
     ctor @Deprecated public GmsFusedBatchOptions();
     method @Deprecated public int getFlags();
diff --git a/core/java/android/location/GeocoderParams.java b/location/lib/java/android/location/GeocoderParams.java
similarity index 65%
rename from core/java/android/location/GeocoderParams.java
rename to location/lib/java/android/location/GeocoderParams.java
index 3ea6364..780ccf4 100644
--- a/core/java/android/location/GeocoderParams.java
+++ b/location/lib/java/android/location/GeocoderParams.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -28,15 +28,15 @@
 import java.util.Objects;
 
 /**
- * This class contains extra parameters to pass to an IGeocodeProvider
- * implementation from the Geocoder class.  Currently this contains the
- * language, country and variant information from the Geocoder's locale
- * as well as the Geocoder client's package name for geocoder server
- * logging.  This information is kept in a separate class to allow for
- * future expansion of the IGeocodeProvider interface.
+ * This class was originally shipped out-of-band from the normal API processes as a separate drop
+ * before SystemApi existed. Now that SystemApi does exist, this class has been retroactively
+ * published through SystemApi.
  *
+ * @deprecated Do not use.
  * @hide
  */
+@Deprecated
+@SystemApi
 public class GeocoderParams implements Parcelable {
 
     private final int mUid;
@@ -52,7 +52,8 @@
         this(Process.myUid(), context.getPackageName(), context.getAttributionTag(), locale);
     }
 
-    private GeocoderParams(int uid, String packageName, String attributionTag, Locale locale) {
+    public GeocoderParams(
+            int uid, String packageName, @Nullable String attributionTag, Locale locale) {
         mUid = uid;
         mPackageName = Objects.requireNonNull(packageName);
         mAttributionTag = attributionTag;
@@ -62,7 +63,6 @@
     /**
      * Returns the client UID.
      */
-    @UnsupportedAppUsage
     public int getClientUid() {
         return mUid;
     }
@@ -70,7 +70,6 @@
     /**
      * Returns the client package name.
      */
-    @UnsupportedAppUsage
     public @NonNull String getClientPackage() {
         return mPackageName;
     }
@@ -78,7 +77,6 @@
     /**
      * Returns the client attribution tag.
      */
-    @UnsupportedAppUsage
     public @Nullable String getClientAttributionTag() {
         return mAttributionTag;
     }
@@ -86,34 +84,38 @@
     /**
      * Returns the locale.
      */
-    @UnsupportedAppUsage
     public @NonNull Locale getLocale() {
         return mLocale;
     }
 
     public static final @NonNull Parcelable.Creator<GeocoderParams> CREATOR =
-        new Parcelable.Creator<GeocoderParams>() {
-            public GeocoderParams createFromParcel(Parcel in) {
-                int uid = in.readInt();
-                String packageName = in.readString8();
-                String attributionTag = in.readString8();
-                String language = in.readString8();
-                String country = in.readString8();
-                String variant = in.readString8();
+            new Parcelable.Creator<>() {
+                public GeocoderParams createFromParcel(Parcel in) {
+                    int uid = in.readInt();
+                    String packageName = in.readString8();
+                    String attributionTag = in.readString8();
+                    String language = in.readString8();
+                    String country = in.readString8();
+                    String variant = in.readString8();
 
-                return new GeocoderParams(uid, packageName, attributionTag,
-                        new Locale(language, country, variant));
-            }
+                    return new GeocoderParams(
+                            uid,
+                            packageName,
+                            attributionTag,
+                            new Locale(language, country, variant));
+                }
 
-            public GeocoderParams[] newArray(int size) {
-                return new GeocoderParams[size];
-            }
-        };
+                public GeocoderParams[] newArray(int size) {
+                    return new GeocoderParams[size];
+                }
+            };
 
+    @Override
     public int describeContents() {
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mUid);
         parcel.writeString8(mPackageName);
diff --git a/location/lib/java/com/android/location/provider/GeocodeProvider.java b/location/lib/java/com/android/location/provider/GeocodeProvider.java
index 05d7935..45077ba 100644
--- a/location/lib/java/com/android/location/provider/GeocodeProvider.java
+++ b/location/lib/java/com/android/location/provider/GeocodeProvider.java
@@ -16,10 +16,13 @@
 
 package com.android.location.provider;
 
+import android.annotation.SystemApi;
 import android.location.Address;
 import android.location.GeocoderParams;
-import android.location.IGeocodeListener;
-import android.location.IGeocodeProvider;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.IGeocodeCallback;
+import android.location.provider.IGeocodeProvider;
+import android.location.provider.ReverseGeocodeRequest;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -27,47 +30,74 @@
 import java.util.List;
 
 /**
- * Base class for geocode providers implemented as unbundled services.
+ * This class was originally shipped out-of-band from the normal API processes as a separate drop
+ * before SystemApi existed. Now that SystemApi does exist, this class has been retroactively
+ * published through SystemApi.
  *
- * <p>Geocode providers can be implemented as services and return the result of
- * {@link GeocodeProvider#getBinder()} in its getBinder() method.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled
- * applications, and must remain API stable. See README.txt in the root
- * of this package for more information.
+ * @deprecated Use {@link android.location.provider.GeocodeProviderBase} instead.
  * @hide
  */
+@Deprecated
+@SystemApi
 public abstract class GeocodeProvider {
 
-    private IGeocodeProvider.Stub mProvider = new IGeocodeProvider.Stub() {
-        @Override
-        public void getFromLocation(double latitude, double longitude, int maxResults,
-                GeocoderParams params, IGeocodeListener listener) {
-            List<Address> results = new ArrayList<>();
-            String error = onGetFromLocation(latitude, longitude, maxResults, params, results);
-            try {
-                listener.onResults(error, results);
-            } catch (RemoteException e) {
-                // ignore
-            }
-        }
+    private final IGeocodeProvider.Stub mProvider =
+            new IGeocodeProvider.Stub() {
+                @Override
+                public void reverseGeocode(
+                        ReverseGeocodeRequest request, IGeocodeCallback callback) {
+                    List<Address> results = new ArrayList<>();
+                    String error =
+                            onGetFromLocation(
+                                    request.getLatitude(),
+                                    request.getLongitude(),
+                                    request.getMaxResults(),
+                                    new GeocoderParams(
+                                            request.getCallingUid(),
+                                            request.getCallingPackage(),
+                                            request.getCallingAttributionTag(),
+                                            request.getLocale()),
+                                    results);
+                    try {
+                        if (error != null) {
+                            callback.onError(error);
+                        } else {
+                            callback.onResults(results);
+                        }
+                    } catch (RemoteException e) {
+                        // ignore
+                    }
+                }
 
-        @Override
-        public void getFromLocationName(String locationName,
-                double lowerLeftLatitude, double lowerLeftLongitude,
-                double upperRightLatitude, double upperRightLongitude, int maxResults,
-                GeocoderParams params, IGeocodeListener listener) {
-            List<Address> results = new ArrayList<>();
-            String error = onGetFromLocationName(locationName, lowerLeftLatitude,
-                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
-                    maxResults, params, results);
-            try {
-                listener.onResults(error, results);
-            } catch (RemoteException e) {
-                // ignore
-            }
-        }
-    };
+                @Override
+                public void forwardGeocode(
+                        ForwardGeocodeRequest request, IGeocodeCallback callback) {
+                    List<Address> results = new ArrayList<>();
+                    String error =
+                            onGetFromLocationName(
+                                    request.getLocationName(),
+                                    request.getLowerLeftLatitude(),
+                                    request.getLowerLeftLongitude(),
+                                    request.getUpperRightLatitude(),
+                                    request.getUpperRightLongitude(),
+                                    request.getMaxResults(),
+                                    new GeocoderParams(
+                                            request.getCallingUid(),
+                                            request.getCallingPackage(),
+                                            request.getCallingAttributionTag(),
+                                            request.getLocale()),
+                                    results);
+                    try {
+                        if (error != null) {
+                            callback.onError(error);
+                        } else {
+                            callback.onResults(results);
+                        }
+                    } catch (RemoteException e) {
+                        // ignore
+                    }
+                }
+            };
 
     /**
      * This method is overridden to implement the
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index ac94a6f..9548525 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3557,6 +3557,36 @@
         }
 
         /**
+         * Set a linear block that contain multiple non-encrypted access unit to this
+         * queue request. Exactly one buffer must be set for a queue request before
+         * calling {@link #queue}. Multiple access units if present must be laid out contiguously
+         * and without gaps and in order. An IllegalArgumentException will be thrown
+         * during {@link #queue} if access units are not laid out contiguously.
+         *
+         * @param block The linear block object
+         * @param infos Represents {@link MediaCodec.BufferInfo} objects to mark
+         *              individual access-unit boundaries and the timestamps associated with it.
+         * @return this object
+         * @throws IllegalStateException if a buffer is already set
+         */
+        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+        public @NonNull QueueRequest setMultiFrameLinearBlock(
+                @NonNull LinearBlock block,
+                @NonNull ArrayDeque<BufferInfo> infos) {
+            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(infos);
+            mCryptoInfos.clear();
+            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}. It is possible
          * to use the same {@link LinearBlock} object for multiple queue
@@ -3691,26 +3721,6 @@
         }
 
         /**
-         * Sets MediaCodec.BufferInfo objects describing the access units
-         * contained in this queue request. Access units must be laid out
-         * contiguously without gaps and in order.
-         *
-         * @param infos Represents {@link MediaCodec.BufferInfo} objects to mark
-         *              individual access-unit boundaries and the timestamps associated with it.
-         *              The buffer is expected to contain the data in a continuous manner.
-         * @return this object
-         */
-        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
-        public @NonNull QueueRequest setBufferInfos(@NonNull ArrayDeque<BufferInfo> infos) {
-            if (!isAccessible()) {
-                throw new IllegalStateException("The request is stale");
-            }
-            mBufferInfos.clear();
-            mBufferInfos.addAll(infos);
-            return this;
-        }
-
-        /**
          * Add an integer parameter.
          * See {@link MediaFormat} for an exhaustive list of supported keys with
          * values of type int, that can also be set with {@link MediaFormat#setInteger}.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 3174c37..1e7bc47 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -20,10 +20,12 @@
 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_IN_PROCESS_SW_AUDIO_CODEC;
 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.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -40,6 +42,8 @@
 import android.util.Rational;
 import android.util.Size;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -1808,6 +1812,55 @@
         }
     }
 
+    /** @hide */
+    @IntDef(prefix = {"SECURITY_MODEL_"}, value = {
+        SECURITY_MODEL_SANDBOXED,
+        SECURITY_MODEL_MEMORY_SAFE,
+        SECURITY_MODEL_TRUSTED_CONTENT_ONLY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SecurityModel {}
+
+    /**
+     * In this model the codec is running in a sandboxed process. Even if a
+     * malicious content was fed to the codecs in this model, the impact will
+     * be contained in the sandboxed process.
+     */
+    @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+    public static final int SECURITY_MODEL_SANDBOXED = 0;
+    /**
+     * In this model the codec is not running in a sandboxed process, but
+     * written in a memory-safe way. It typically means that the software
+     * implementation of the codec is written in a memory-safe language such
+     * as Rust.
+     */
+    @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+    public static final int SECURITY_MODEL_MEMORY_SAFE = 1;
+    /**
+     * In this model the codec is suitable only for trusted content where
+     * the input can be verified to be well-formed and no malicious actor
+     * can alter it. For example, codecs in this model are not suitable
+     * for arbitrary media downloaded from the internet or present in a user
+     * directory. On the other hand, they could be suitable for media encoded
+     * in the backend that the app developer wholly controls.
+     * <p>
+     * Codecs with this security model is not included in
+     * {@link MediaCodecList#REGULAR_CODECS}, but included in
+     * {@link MediaCodecList#ALL_CODECS}.
+     */
+    @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+    public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2;
+
+    /**
+     * Query the security model of the codec.
+     */
+    @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+    @SecurityModel
+    public int getSecurityModel() {
+        // TODO b/297922713 --- detect security model of out-of-sandbox codecs
+        return SECURITY_MODEL_SANDBOXED;
+    }
+
     /**
      * A class that supports querying the video capabilities of a codec.
      */
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 5e40eee..7b83842 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
+
 import static com.android.media.codec.flags.Flags.FLAG_CODEC_IMPORTANCE;
 import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
 
@@ -1715,6 +1717,58 @@
     @FlaggedApi(FLAG_CODEC_IMPORTANCE)
     public static final String KEY_IMPORTANCE = "importance";
 
+    /** @hide */
+    @IntDef(flag = true, prefix = {"FLAG_SECURITY_MODEL_"}, value = {
+        FLAG_SECURITY_MODEL_SANDBOXED,
+        FLAG_SECURITY_MODEL_MEMORY_SAFE,
+        FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SecurityModelFlag {}
+
+    /**
+     * Flag for {@link MediaCodecInfo#SECURITY_MODEL_SANDBOXED}.
+     */
+    @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+    public static final int FLAG_SECURITY_MODEL_SANDBOXED =
+            (1 << MediaCodecInfo.SECURITY_MODEL_SANDBOXED);
+    /**
+     * Flag for {@link MediaCodecInfo#SECURITY_MODEL_MEMORY_SAFE}.
+     */
+    @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+    public static final int FLAG_SECURITY_MODEL_MEMORY_SAFE =
+            (1 << MediaCodecInfo.SECURITY_MODEL_MEMORY_SAFE);
+    /**
+     * Flag for {@link MediaCodecInfo#SECURITY_MODEL_TRUSTED_CONTENT_ONLY}.
+     */
+    @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+    public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY =
+            (1 << MediaCodecInfo.SECURITY_MODEL_TRUSTED_CONTENT_ONLY);
+
+    /**
+     * A key describing the requested security model as flags.
+     * <p>
+     * The associated value is a flag of the following values:
+     * {@link FLAG_SECURITY_MODEL_SANDBOXED},
+     * {@link FLAG_SECURITY_MODEL_MEMORY_SAFE},
+     * {@link FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY}. The default value is
+     * {@link FLAG_SECURITY_MODEL_SANDBOXED}.
+     * <p>
+     * When passed to {@link MediaCodecList#findDecoderForFormat} or
+     * {@link MediaCodecList#findEncoderForFormat}, MediaCodecList filters
+     * the security model of the codecs according to this flag value.
+     * <p>
+     * When passed to {@link MediaCodec#configure}, MediaCodec verifies
+     * the security model matches the flag value passed, and throws
+     * {@link java.lang.IllegalArgumentException} if the model does not match.
+     * <p>
+     * @see MediaCodecInfo#getSecurityModel
+     * @see MediaCodecList#findDecoderForFormat
+     * @see MediaCodecList#findEncoderForFormat
+     */
+    @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+    public static final String KEY_SECURITY_MODEL = "security-model";
+
     /* package private */ MediaFormat(@NonNull Map<String, Object> map) {
         mMap = map;
     }
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 3254a39..f264b16 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -44,6 +44,8 @@
 import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -138,6 +140,11 @@
     private boolean mCategoryOtherServiceEnabled;
 
     /**
+     * Whether the NFC stack should default to Observe Mode when this preferred service.
+     */
+    private boolean mDefaultToObserveMode;
+
+    /**
      * @hide
      */
     @UnsupportedAppUsage
@@ -257,6 +264,9 @@
                         com.android.internal.R.styleable.HostApduService_settingsActivity);
                 mOffHostName = null;
                 mStaticOffHostName = mOffHostName;
+                mDefaultToObserveMode = sa.getBoolean(
+                        R.styleable.HostApduService_defaultToObserveMode,
+                        false);
                 sa.recycle();
             } else {
                 TypedArray sa = res.obtainAttributes(attrs,
@@ -276,6 +286,9 @@
                         com.android.internal.R.styleable.HostApduService_settingsActivity);
                 mOffHostName = sa.getString(
                         com.android.internal.R.styleable.OffHostApduService_secureElementName);
+                mDefaultToObserveMode = sa.getBoolean(
+                        R.styleable.HostApduService_defaultToObserveMode,
+                        false);
                 if (mOffHostName != null) {
                     if (mOffHostName.equals("eSE")) {
                         mOffHostName = "eSE1";
@@ -611,6 +624,25 @@
     }
 
     /**
+     * Returns whether the NFC stack should default to observe mode when this servise is preferred.
+     * @return whether the NFC stack should default to observe mode when this servise is preferred
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
+    public boolean defaultToObserveMode() {
+        return mDefaultToObserveMode;
+    }
+
+    /**
+     * Sets whether the NFC stack should default to observe mode when this servise is preferred.
+     * @param defaultToObserveMode whether the NFC stack should default to observe mode when this
+     *                             servise is preferred
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
+    public void setDefaultToObserveMode(boolean defaultToObserveMode) {
+        mDefaultToObserveMode = defaultToObserveMode;
+    }
+
+    /**
      * Returns description of service.
      * @return user readable description of service
      */
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 4305d91..53f2caf 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -771,6 +771,9 @@
     <!-- Permission required for CTS test - CtsDevicePolicyManagerTestCases -->
     <uses-permission android:name="android.permission.READ_NEARBY_STREAMING_POLICY" />
 
+    <!-- Permission required for CTS test - CtsDevicePolicyTestCases -->
+    <uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING" />
+
     <!-- Permission required for CTS test - CtsKeystoreTestCases -->
     <uses-permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION" />
 
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectView.kt
new file mode 100644
index 0000000..aad593e
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectView.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.surfaceeffects.loadingeffect
+
+import android.content.Context
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+
+/** Custom View for drawing the [LoadingEffect] with [Canvas.drawPaint]. */
+open class LoadingEffectView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+
+    private var paint: Paint? = null
+    private var blendMode: BlendMode = BlendMode.SRC_OVER
+
+    override fun onDraw(canvas: Canvas) {
+        if (!canvas.isHardwareAccelerated) {
+            return
+        }
+        paint?.let { canvas.drawPaint(it) }
+    }
+
+    /** Designed to be called on [LoadingEffect.PaintDrawCallback.onDraw]. */
+    fun draw(paint: Paint) {
+        this.paint = paint
+        this.paint!!.blendMode = blendMode
+
+        invalidate()
+    }
+
+    /** Sets the blend mode of the [Paint]. */
+    fun setBlendMode(blendMode: BlendMode) {
+        this.blendMode = blendMode
+    }
+}
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 5db9eee..109e63c 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -67,6 +67,18 @@
         android:background="@drawable/qs_media_outline_layout_bg"
         />
 
+    <com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView
+        android:id="@+id/loading_effect_view"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/qs_media_session_height_expanded"
+        app:layout_constraintStart_toStartOf="@id/album_art"
+        app:layout_constraintEnd_toEndOf="@id/album_art"
+        app:layout_constraintTop_toTopOf="@id/album_art"
+        app:layout_constraintBottom_toBottomOf="@id/album_art"
+        android:clipToOutline="true"
+        android:background="@drawable/qs_media_outline_layout_bg"
+        />
+
     <!-- Guideline for output switcher -->
     <androidx.constraintlayout.widget.Guideline
         android:id="@+id/center_vertical_guideline"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e401c71..57c4230 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1416,6 +1416,9 @@
     <!-- Indication on the keyguard that appears when a trust agents unlocks the device. [CHAR LIMIT=40] -->
     <string name="keyguard_indication_trust_unlocked">Kept unlocked by TrustAgent</string>
 
+    <!-- Message asking the user to authenticate with primary authentication methods (PIN/pattern/password) or biometrics after the device is locked by adaptive auth. [CHAR LIMIT=60] -->
+    <string name="kg_prompt_after_adaptive_auth_lock">Theft protection\nDevice locked, too many unlock attempts</string>
+
     <!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
     <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
 
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index c053b33..2f2b10f 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -55,6 +55,15 @@
         app:layout_constraintBottom_toBottomOf="@+id/album_art" />
 
     <Constraint
+        android:id="@+id/loading_effect_view"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/qs_media_session_height_collapsed"
+        app:layout_constraintStart_toStartOf="@+id/album_art"
+        app:layout_constraintEnd_toEndOf="@+id/album_art"
+        app:layout_constraintTop_toTopOf="@+id/album_art"
+        app:layout_constraintBottom_toBottomOf="@+id/album_art" />
+
+    <Constraint
         android:id="@+id/header_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 8bf7560d..0140d52 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -48,6 +48,15 @@
         app:layout_constraintBottom_toBottomOf="@+id/album_art" />
 
     <Constraint
+        android:id="@+id/loading_effect_view"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/qs_media_session_height_expanded"
+        app:layout_constraintStart_toStartOf="@+id/album_art"
+        app:layout_constraintEnd_toEndOf="@+id/album_art"
+        app:layout_constraintTop_toTopOf="@+id/album_art"
+        app:layout_constraintBottom_toBottomOf="@+id/album_art" />
+
+    <Constraint
         android:id="@+id/header_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 3585feb..84c8ea7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -19,6 +19,7 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.WindowInsets.Type.ime;
 
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_ADAPTIVE_AUTH_REQUEST;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
@@ -126,6 +127,8 @@
                 return R.string.kg_prompt_reason_timeout_password;
             case PROMPT_REASON_TRUSTAGENT_EXPIRED:
                 return R.string.kg_prompt_reason_timeout_password;
+            case PROMPT_REASON_ADAPTIVE_AUTH_REQUEST:
+                return R.string.kg_prompt_after_adaptive_auth_lock;
             case PROMPT_REASON_NONE:
                 return 0;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index db7ff88..bf8900d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -331,6 +331,9 @@
             case PROMPT_REASON_TRUSTAGENT_EXPIRED:
                 resId = R.string.kg_prompt_reason_timeout_pattern;
                 break;
+            case PROMPT_REASON_ADAPTIVE_AUTH_REQUEST:
+                resId = R.string.kg_prompt_after_adaptive_auth_lock;
+                break;
             case PROMPT_REASON_NONE:
                 break;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index fcff0db..bcab6f0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -16,6 +16,7 @@
 
 package com.android.keyguard;
 
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_ADAPTIVE_AUTH_REQUEST;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
@@ -138,6 +139,8 @@
                 return R.string.kg_prompt_reason_timeout_pin;
             case PROMPT_REASON_TRUSTAGENT_EXPIRED:
                 return R.string.kg_prompt_reason_timeout_pin;
+            case PROMPT_REASON_ADAPTIVE_AUTH_REQUEST:
+                return R.string.kg_prompt_after_adaptive_auth_lock;
             case PROMPT_REASON_NONE:
                 return 0;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 83b1a2c..3e87c1b6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -67,6 +67,11 @@
     int PROMPT_REASON_TRUSTAGENT_EXPIRED = 8;
 
     /**
+     * Some auth is required because adaptive auth has determined risk
+     */
+    int PROMPT_REASON_ADAPTIVE_AUTH_REQUEST = 9;
+
+    /**
      * Strong auth is required because the device has just booted because of an automatic
      * mainline update.
      */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 536f3af..5d073f1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -35,6 +35,7 @@
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
 import static android.os.BatteryManager.CHARGING_POLICY_DEFAULT;
 
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -1570,6 +1571,14 @@
         return isEncrypted || isLockDown;
     }
 
+    /**
+     * Whether the device is locked by adaptive auth
+     */
+    public boolean isDeviceLockedByAdaptiveAuth(int userId) {
+        return containsFlag(mStrongAuthTracker.getStrongAuthForUser(userId),
+                SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST);
+    }
+
     private boolean containsFlag(int haystack, int needle) {
         return (haystack & needle) != 0;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
index 7b4be02..9c28f1c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -115,17 +115,11 @@
     }
 
     private var overlayView: View? = null
-    private var lottie: LottieAnimationView? = null
 
     /** Show the side fingerprint sensor indicator */
     private fun show() {
-        overlayView?.let {
-            if (it.isAttachedToWindow) {
-                lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
-                lottie?.pauseAnimation()
-                lottie?.removeAllLottieOnCompositionLoadedListener()
-                windowManager.get().removeView(it)
-            }
+        if (overlayView?.isAttachedToWindow == true) {
+            return
         }
 
         overlayView = layoutInflater.get().inflate(R.layout.sidefps_view, null, false)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
index 8197145..c25e748 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
@@ -50,6 +50,7 @@
 import com.android.systemui.res.R.string.kg_primary_auth_locked_out_password
 import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pattern
 import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pin
+import com.android.systemui.res.R.string.kg_prompt_after_adaptive_auth_lock
 import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
 import com.android.systemui.res.R.string.kg_prompt_after_update_password
 import com.android.systemui.res.R.string.kg_prompt_after_update_pattern
@@ -208,6 +209,11 @@
                     } else {
                         faceLockedOut(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
                     }
+                } else if (flags.isSomeAuthRequiredAfterAdaptiveAuthRequest) {
+                    authRequiredAfterAdaptiveAuthRequest(
+                        currentSecurityMode,
+                        isFingerprintAuthCurrentlyAllowed.value
+                    )
                 } else if (
                     trustOrBiometricsAvailable &&
                         flags.strongerAuthRequiredAfterNonStrongBiometricsTimeout
@@ -464,6 +470,34 @@
     }.toMessage()
 }
 
+private fun authRequiredAfterAdaptiveAuthRequest(
+    securityMode: SecurityMode,
+    fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+    return if (fpAuthIsAllowed) authRequiredAfterAdaptiveAuthRequestFingerprintAllowed(securityMode)
+    else
+        return when (securityMode) {
+            SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_adaptive_auth_lock)
+            SecurityMode.Password ->
+                Pair(keyguard_enter_password, kg_prompt_after_adaptive_auth_lock)
+            SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_adaptive_auth_lock)
+            else -> Pair(0, 0)
+        }.toMessage()
+}
+
+private fun authRequiredAfterAdaptiveAuthRequestFingerprintAllowed(
+    securityMode: SecurityMode
+): BouncerMessageModel {
+    return when (securityMode) {
+        SecurityMode.Pattern ->
+            Pair(kg_unlock_with_pattern_or_fp, kg_prompt_after_adaptive_auth_lock)
+        SecurityMode.Password ->
+            Pair(kg_unlock_with_password_or_fp, kg_prompt_after_adaptive_auth_lock)
+        SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_prompt_after_adaptive_auth_lock)
+        else -> Pair(0, 0)
+    }.toMessage()
+}
+
 private fun authRequiredAfterUserLockdown(securityMode: SecurityMode): BouncerMessageModel {
     return when (securityMode) {
         SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_user_lockdown_pattern)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index e23ec89..00ec1a1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -404,6 +404,7 @@
     public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE = 11;
     public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP = 12;
     public static final int INDICATION_IS_DISMISSIBLE = 13;
+    public static final int INDICATION_TYPE_ADAPTIVE_AUTH = 14;
 
     @IntDef({
             INDICATION_TYPE_NONE,
@@ -419,7 +420,8 @@
             INDICATION_TYPE_REVERSE_CHARGING,
             INDICATION_TYPE_BIOMETRIC_MESSAGE,
             INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
-            INDICATION_IS_DISMISSIBLE
+            INDICATION_IS_DISMISSIBLE,
+            INDICATION_TYPE_ADAPTIVE_AUTH
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface IndicationType{}
@@ -455,6 +457,8 @@
                 return "biometric_message";
             case INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP:
                 return "biometric_message_followup";
+            case INDICATION_TYPE_ADAPTIVE_AUTH:
+                return "adaptive_auth";
             default:
                 return "unknown[" + type + "]";
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 63fd608..641b967 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -30,6 +30,7 @@
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_OCCLUSION;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_UNLOCK_ANIMATION;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -920,15 +921,17 @@
                 return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
             } else if ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
+            } else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0
+                    || mUpdateMonitor.isFingerprintLockedOut())) {
+                return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
+            } else if ((strongAuth & SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST) != 0) {
+                return KeyguardSecurityView.PROMPT_REASON_ADAPTIVE_AUTH_REQUEST;
             } else if (trustAgentsEnabled
                     && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
             } else if (trustAgentsEnabled
                     && (strongAuth & SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED;
-            } else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0
-                    || mUpdateMonitor.isFingerprintLockedOut())) {
-                return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
             } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
             } else if (any && (strongAuth
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/AuthenticationFlags.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/AuthenticationFlags.kt
index cf5b88f..08904b6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/AuthenticationFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/AuthenticationFlags.kt
@@ -60,6 +60,12 @@
             LockPatternUtils.StrongAuthTracker
                 .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT
         )
+
+    val isSomeAuthRequiredAfterAdaptiveAuthRequest =
+        containsFlag(
+            flag,
+            LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST
+        )
 }
 
 private fun containsFlag(haystack: Int, needle: Int): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
index 1b14f75..898eacf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
@@ -25,8 +25,9 @@
 import android.widget.TextView
 import androidx.constraintlayout.widget.Barrier
 import com.android.internal.widget.CachingIconView
-import com.android.systemui.res.R
 import com.android.systemui.media.controls.models.GutsViewHolder
+import com.android.systemui.res.R
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView
 import com.android.systemui.surfaceeffects.ripple.MultiRippleView
 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView
 import com.android.systemui.util.animation.TransitionLayout
@@ -42,6 +43,7 @@
     val multiRippleView = itemView.requireViewById<MultiRippleView>(R.id.touch_ripple_view)
     val turbulenceNoiseView =
         itemView.requireViewById<TurbulenceNoiseView>(R.id.turbulence_noise_view)
+    val loadingEffectView = itemView.requireViewById<LoadingEffectView>(R.id.loading_effect_view)
     val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
     val titleText = itemView.requireViewById<TextView>(R.id.header_title)
     val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
@@ -171,6 +173,7 @@
             setOf(
                 R.id.album_art,
                 R.id.turbulence_noise_view,
+                R.id.loading_effect_view,
                 R.id.touch_ripple_view,
             )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
index c87fd14..952f9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
@@ -29,6 +29,7 @@
 import com.android.settingslib.Utils
 import com.android.systemui.media.controls.models.player.MediaViewHolder
 import com.android.systemui.monet.ColorScheme
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect
 import com.android.systemui.surfaceeffects.ripple.MultiRippleController
 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController
 
@@ -118,6 +119,7 @@
         turbulenceNoiseController,
         ::AnimatingColorTransition
     )
+    var loadingEffect: LoadingEffect? = null
 
     val bgColor = context.getColor(com.google.android.material.R.color.material_dynamic_neutral20)
     val surfaceColor =
@@ -128,7 +130,6 @@
             mediaViewHolder.albumView.backgroundTintList = colorList
             mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor)
         }
-
     val accentPrimary =
         animatingColorTransitionFactory(
             loadDefaultColor(R.attr.textColorPrimary),
@@ -139,6 +140,7 @@
             mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary)
             multiRippleController.updateColor(accentPrimary)
             turbulenceNoiseController.updateNoiseColor(accentPrimary)
+            loadingEffect?.updateColor(accentPrimary)
         }
 
     val accentSecondary =
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index aa92814..e97c9d3d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -41,6 +41,7 @@
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Matrix;
+import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.BitmapDrawable;
@@ -81,6 +82,7 @@
 import com.android.internal.widget.CachingIconView;
 import com.android.settingslib.widget.AdaptiveIcon;
 import com.android.systemui.ActivityIntentHelper;
+import com.android.systemui.Flags;
 import com.android.systemui.animation.ActivityTransitionAnimator;
 import com.android.systemui.animation.GhostedViewTransitionAnimatorController;
 import com.android.systemui.bluetooth.BroadcastDialogController;
@@ -111,6 +113,9 @@
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect;
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState;
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView;
 import com.android.systemui.surfaceeffects.ripple.MultiRippleController;
 import com.android.systemui.surfaceeffects.ripple.MultiRippleView;
 import com.android.systemui.surfaceeffects.ripple.RippleAnimation;
@@ -248,13 +253,34 @@
     private String mCurrentBroadcastApp;
     private MultiRippleController mMultiRippleController;
     private TurbulenceNoiseController mTurbulenceNoiseController;
+    private LoadingEffect mLoadingEffect;
     private final GlobalSettings mGlobalSettings;
-
+    private final Random mRandom = new Random();
     private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig;
     private boolean mWasPlaying = false;
     private boolean mButtonClicked = false;
 
-    private final Random mRandom = new Random();
+    private final LoadingEffect.Companion.PaintDrawCallback mNoiseDrawCallback =
+            new LoadingEffect.Companion.PaintDrawCallback() {
+                @Override
+                public void onDraw(@NonNull Paint loadingPaint) {
+                    mMediaViewHolder.getLoadingEffectView().draw(loadingPaint);
+                }
+            };
+    private final LoadingEffect.Companion.AnimationStateChangedCallback mStateChangedCallback =
+            new LoadingEffect.Companion.AnimationStateChangedCallback() {
+                @Override
+                public void onStateChanged(@NonNull AnimationState oldState,
+                        @NonNull AnimationState newState) {
+                    LoadingEffectView loadingEffectView =
+                            mMediaViewHolder.getLoadingEffectView();
+                    if (newState == AnimationState.NOT_PLAYING) {
+                        loadingEffectView.setVisibility(View.INVISIBLE);
+                    } else {
+                        loadingEffectView.setVisibility(View.VISIBLE);
+                    }
+                }
+            };
 
     /**
      * Initialize a new control panel
@@ -456,6 +482,10 @@
 
         TurbulenceNoiseView turbulenceNoiseView = vh.getTurbulenceNoiseView();
         turbulenceNoiseView.setBlendMode(BlendMode.SCREEN);
+        LoadingEffectView loadingEffectView = vh.getLoadingEffectView();
+        loadingEffectView.setBlendMode(BlendMode.SCREEN);
+        loadingEffectView.setVisibility(View.INVISIBLE);
+
         mTurbulenceNoiseController = new TurbulenceNoiseController(turbulenceNoiseView);
 
         mColorSchemeTransition = new ColorSchemeTransition(
@@ -587,22 +617,41 @@
             }
         }
 
-        // Turbulence noise
         if (shouldPlayTurbulenceNoise()) {
+            // Need to create the config here to get the correct view size and color.
             if (mTurbulenceNoiseAnimationConfig == null) {
                 mTurbulenceNoiseAnimationConfig =
-                        createTurbulenceNoiseAnimation();
+                        createTurbulenceNoiseConfig();
             }
-            // Color will be correctly updated in ColorSchemeTransition.
-            mTurbulenceNoiseController.play(
-                    Type.SIMPLEX_NOISE,
-                    mTurbulenceNoiseAnimationConfig
-            );
-            mMainExecutor.executeDelayed(
-                    mTurbulenceNoiseController::finish,
-                    TURBULENCE_NOISE_PLAY_DURATION
-            );
+
+            if (Flags.shaderlibLoadingEffectRefactor()) {
+                if (mLoadingEffect == null) {
+                    mLoadingEffect = new LoadingEffect(
+                            Type.SIMPLEX_NOISE,
+                            mTurbulenceNoiseAnimationConfig,
+                            mNoiseDrawCallback,
+                            mStateChangedCallback
+                    );
+                    mColorSchemeTransition.setLoadingEffect(mLoadingEffect);
+                }
+
+                mLoadingEffect.play();
+                mMainExecutor.executeDelayed(
+                        mLoadingEffect::finish,
+                        TURBULENCE_NOISE_PLAY_DURATION
+                );
+            } else {
+                mTurbulenceNoiseController.play(
+                        Type.SIMPLEX_NOISE,
+                        mTurbulenceNoiseAnimationConfig
+                );
+                mMainExecutor.executeDelayed(
+                        mTurbulenceNoiseController::finish,
+                        TURBULENCE_NOISE_PLAY_DURATION
+                );
+            }
         }
+
         mButtonClicked = false;
         mWasPlaying = isPlaying();
 
@@ -1232,7 +1281,13 @@
         return mButtonClicked && !mWasPlaying && isPlaying();
     }
 
-    private TurbulenceNoiseAnimationConfig createTurbulenceNoiseAnimation() {
+    private TurbulenceNoiseAnimationConfig createTurbulenceNoiseConfig() {
+        View targetView = Flags.shaderlibLoadingEffectRefactor()
+                ? mMediaViewHolder.getLoadingEffectView() :
+                mMediaViewHolder.getTurbulenceNoiseView();
+        int width = targetView.getWidth();
+        int height = targetView.getHeight();
+
         return new TurbulenceNoiseAnimationConfig(
                 /* gridCount= */ 2.14f,
                 TurbulenceNoiseAnimationConfig.DEFAULT_LUMINOSITY_MULTIPLIER,
@@ -1242,10 +1297,11 @@
                 /* noiseMoveSpeedX= */ 0.42f,
                 /* noiseMoveSpeedY= */ 0f,
                 TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_SPEED_Z,
+                // Color will be correctly updated in ColorSchemeTransition.
                 /* color= */ mColorSchemeTransition.getAccentPrimary().getCurrentColor(),
                 /* backgroundColor= */ Color.BLACK,
-                /* width= */ mMediaViewHolder.getTurbulenceNoiseView().getWidth(),
-                /* height= */ mMediaViewHolder.getTurbulenceNoiseView().getHeight(),
+                width,
+                height,
                 TurbulenceNoiseAnimationConfig.DEFAULT_MAX_DURATION_IN_MILLIS,
                 /* easeInDuration= */ 1350f,
                 /* easeOutDuration= */ 1350f,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index 092f1ed..152f193 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -44,6 +44,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.RegisterStatusBarResult;
 import com.android.settingslib.applications.InterestingConfigChanges;
@@ -89,7 +90,16 @@
     private final TaskbarDelegate mTaskbarDelegate;
     private final NavBarHelper mNavBarHelper;
     private int mNavMode;
+    /**
+     * Indicates whether the active display is a large screen, e.g. tablets, foldable devices in
+     * the unfolded state.
+     */
     @VisibleForTesting boolean mIsLargeScreen;
+    /**
+     * Indicates whether the device is a phone, rather than everything else (e.g. foldables,
+     * tablets) is considered not a handheld device.
+     */
+    @VisibleForTesting boolean mIsPhone;
 
     /** A displayId - nav bar maps. */
     @VisibleForTesting
@@ -139,6 +149,8 @@
                 dumpManager, autoHideController, lightBarController, pipOptional,
                 backAnimation.orElse(null), taskStackChangeListeners);
         mIsLargeScreen = isLargeScreen(mContext);
+        mIsPhone =
+                mContext.getResources().getIntArray(R.array.config_foldedDeviceStates).length == 0;
         dumpManager.registerDumpable(this);
     }
 
@@ -253,9 +265,8 @@
 
     /** @return {@code true} if taskbar is enabled, false otherwise */
     private boolean initializeTaskbarIfNecessary() {
-        // Enable for large screens or (phone AND flag is set); assuming phone = !mIsLargeScreen
-        boolean taskbarEnabled = (mIsLargeScreen || enableTaskbarNavbarUnification())
-                && shouldCreateNavBarAndTaskBar(mContext.getDisplayId());
+        boolean taskbarEnabled = supportsTaskbar() && shouldCreateNavBarAndTaskBar(
+                mContext.getDisplayId());
 
         if (taskbarEnabled) {
             Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary");
@@ -274,6 +285,12 @@
         return taskbarEnabled;
     }
 
+    @VisibleForTesting
+    boolean supportsTaskbar() {
+        // Enable for tablets, unfolded state on a foldable device or (non handheld AND flag is set)
+        return mIsLargeScreen || (!mIsPhone && enableTaskbarNavbarUnification());
+    }
+
     private final CommandQueue.Callbacks mCommandQueueCallbacks = new CommandQueue.Callbacks() {
         @Override
         public void onDisplayRemoved(int displayId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 14230ba..19fe60a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import static android.adaptiveauth.Flags.enableAdaptiveAuth;
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE;
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE;
@@ -32,6 +33,7 @@
 import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_IS_DISMISSIBLE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ADAPTIVE_AUTH;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
@@ -454,6 +456,9 @@
         updateLockScreenAlignmentMsg();
         updateLockScreenLogoutView();
         updateLockScreenPersistentUnlockMsg();
+        if (enableAdaptiveAuth()) {
+            updateLockScreenAdaptiveAuthMsg(userId);
+        }
     }
 
     private void updateOrganizedOwnedDevice() {
@@ -740,6 +745,22 @@
         }
     }
 
+    private void updateLockScreenAdaptiveAuthMsg(int userId) {
+        final boolean deviceLocked = mKeyguardUpdateMonitor.isDeviceLockedByAdaptiveAuth(userId);
+        if (deviceLocked) {
+            mRotateTextViewController.updateIndication(
+                    INDICATION_TYPE_ADAPTIVE_AUTH,
+                    new KeyguardIndication.Builder()
+                            .setMessage(mContext
+                                    .getString(R.string.kg_prompt_after_adaptive_auth_lock))
+                            .setTextColor(mInitialTextColorState)
+                            .build(),
+                    true);
+        } else {
+            mRotateTextViewController.hideIndication(INDICATION_TYPE_ADAPTIVE_AUTH);
+        }
+    }
+
     private boolean isOrganizationOwnedDevice() {
         return mDevicePolicyManager.isDeviceManaged()
                 || mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 2a4753d..9916ef6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -749,7 +749,7 @@
                 || isNotifUserRedacted;
 
         boolean notificationRequestsRedaction =
-                ent.getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
+                ent.isNotificationVisibilityPrivate();
         boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey());
 
         if (keyguardPrivateNotifications()) {
@@ -767,9 +767,7 @@
         }
         NotificationEntry entry = mCommonNotifCollectionLazy.get().getEntry(key);
         if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) {
-            return entry != null && entry.getRanking().getChannel() != null
-                    && entry.getRanking().getChannel().getLockscreenVisibility()
-                    == Notification.VISIBILITY_PRIVATE;
+            return entry != null && entry.isChannelVisibilityPrivate();
         } else {
             return entry != null
                     && entry.getRanking().getLockscreenVisibilityOverride()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 8678f0a..e111525 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -998,6 +998,23 @@
         return style == null ? "nostyle" : style.getSimpleName();
     }
 
+    /**
+     * Return {@code true} if notification's visibility is {@link Notification.VISIBILITY_PRIVATE}
+     */
+    public boolean isNotificationVisibilityPrivate() {
+        return getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
+    }
+
+    /**
+     * Return {@code true} if notification's channel lockscreen visibility is
+     * {@link Notification.VISIBILITY_PRIVATE}
+     */
+    public boolean isChannelVisibilityPrivate() {
+        return getRanking().getChannel() != null
+                && getRanking().getChannel().getLockscreenVisibility()
+                == Notification.VISIBILITY_PRIVATE;
+    }
+
     /** Information about a suggestion that is being edited. */
     public static class EditedSuggestionInfo {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
index 2b0a92c..6956a7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -221,10 +221,15 @@
         // Exempt foreground service notifications from protection in effort to keep screen share
         // stop actions easily accessible
         StatusBarNotification sbn = entry.getSbn();
-        if (sbn.getNotification().isFgsOrUij()) {
-            return !sbn.getPackageName().equals(projection.getPackageName());
+        if (sbn.getNotification().isFgsOrUij()
+                && sbn.getPackageName().equals(projection.getPackageName())) {
+            return false;
         }
 
-        return true;
+        // Only protect/redact notifications if the developer has not explicitly set notification
+        // visibility as public and users has not adjusted default channel visibility to private
+        boolean notificationRequestsRedaction = entry.isNotificationVisibilityPrivate();
+        boolean userForcesRedaction = entry.isChannelVisibilityPrivate();
+        return notificationRequestsRedaction || userForcesRedaction;
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 2732047..0957748 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -21,6 +21,7 @@
 import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT;
 import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER;
 
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
@@ -650,6 +651,25 @@
     }
 
     @Test
+    public void testBouncerPrompt_deviceLockedByAdaptiveAuth() {
+        // GIVEN no trust agents enabled and biometrics aren't enrolled
+        when(mUpdateMonitor.isTrustUsuallyManaged(anyInt())).thenReturn(false);
+        when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(false);
+
+        // WHEN the strong auth reason is SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST
+        KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+                mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+        when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+        when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+        when(strongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+                SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST);
+
+        // THEN the bouncer prompt reason should return PROMPT_REASON_ADAPTIVE_AUTH_REQUEST
+        assertEquals(KeyguardSecurityView.PROMPT_REASON_ADAPTIVE_AUTH_REQUEST,
+                mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+    }
+
+    @Test
     public void testBouncerPrompt_deviceRestartedDueToMainlineUpdate() {
         // GIVEN biometrics enrolled
         when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index 5996502..c896486 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -40,6 +40,7 @@
 import android.media.session.MediaSession
 import android.media.session.PlaybackState
 import android.os.Bundle
+import android.platform.test.annotations.EnableFlags
 import android.provider.Settings
 import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
 import android.testing.AndroidTestingRunner
@@ -61,6 +62,7 @@
 import com.android.internal.logging.InstanceId
 import com.android.internal.widget.CachingIconView
 import com.android.systemui.ActivityIntentHelper
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bluetooth.BroadcastDialogController
 import com.android.systemui.broadcast.BroadcastSender
@@ -88,6 +90,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView
 import com.android.systemui.surfaceeffects.ripple.MultiRippleView
 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig
 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView
@@ -190,6 +193,7 @@
     private lateinit var dismissText: TextView
     private lateinit var multiRippleView: MultiRippleView
     private lateinit var turbulenceNoiseView: TurbulenceNoiseView
+    private lateinit var loadingEffectView: LoadingEffectView
 
     private lateinit var session: MediaSession
     private lateinit var device: MediaDeviceData
@@ -402,6 +406,7 @@
 
         multiRippleView = MultiRippleView(context, null)
         turbulenceNoiseView = TurbulenceNoiseView(context, null)
+        loadingEffectView = LoadingEffectView(context, null)
 
         whenever(viewHolder.player).thenReturn(view)
         whenever(viewHolder.appIcon).thenReturn(appIcon)
@@ -447,6 +452,7 @@
 
         whenever(viewHolder.multiRippleView).thenReturn(multiRippleView)
         whenever(viewHolder.turbulenceNoiseView).thenReturn(turbulenceNoiseView)
+        whenever(viewHolder.loadingEffectView).thenReturn(loadingEffectView)
     }
 
     /** Initialize elements for the recommendation view holder */
@@ -2429,6 +2435,7 @@
 
         mainExecutor.execute {
             assertThat(turbulenceNoiseView.visibility).isEqualTo(View.VISIBLE)
+            assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
 
             clock.advanceTime(
                 MediaControlPanel.TURBULENCE_NOISE_PLAY_DURATION +
@@ -2436,6 +2443,40 @@
             )
 
             assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
+            assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
+        }
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_SHADERLIB_LOADING_EFFECT_REFACTOR)
+    fun playTurbulenceNoise_newLoadingEffect_finishesAfterDuration() {
+        val semanticActions =
+            MediaButton(
+                playOrPause =
+                    MediaAction(
+                        icon = null,
+                        action = {},
+                        contentDescription = "play",
+                        background = null
+                    )
+            )
+        val data = mediaData.copy(semanticActions = semanticActions)
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(data, KEY)
+
+        viewHolder.actionPlayPause.callOnClick()
+
+        mainExecutor.execute {
+            assertThat(loadingEffectView.visibility).isEqualTo(View.VISIBLE)
+            assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
+
+            clock.advanceTime(
+                MediaControlPanel.TURBULENCE_NOISE_PLAY_DURATION +
+                    TurbulenceNoiseAnimationConfig.DEFAULT_EASING_DURATION_IN_MILLIS.toLong()
+            )
+
+            assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
+            assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
         }
     }
 
@@ -2458,6 +2499,30 @@
         viewHolder.action0.callOnClick()
 
         assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_SHADERLIB_LOADING_EFFECT_REFACTOR)
+    fun playTurbulenceNoise_newLoadingEffect_whenPlaybackStateIsNotPlaying_doesNotPlayTurbulence() {
+        val semanticActions =
+            MediaButton(
+                custom0 =
+                    MediaAction(
+                        icon = null,
+                        action = {},
+                        contentDescription = "custom0",
+                        background = null
+                    ),
+            )
+        val data = mediaData.copy(semanticActions = semanticActions)
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(data, KEY)
+
+        viewHolder.action0.callOnClick()
+
+        assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
index bfb18c8..52859cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
@@ -22,6 +22,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -289,32 +291,43 @@
         verify(mCommandQueue, never()).addCallback(any(TaskbarDelegate.class));
     }
 
-
     @Test
     public void testConfigurationChange_taskbarNotInitialized() {
         Configuration configuration = mContext.getResources().getConfiguration();
-        when(Utilities.isLargeScreen(any())).thenReturn(true);
+        mNavigationBarController.mIsLargeScreen = true;
         mNavigationBarController.onConfigChanged(configuration);
         verify(mTaskbarDelegate, never()).onConfigurationChanged(configuration);
     }
 
     @Test
-    public void testConfigurationChangeUnfolding_taskbarInitialized() {
+    public void testConfigurationChange_taskbarInitialized() {
         Configuration configuration = mContext.getResources().getConfiguration();
-        when(Utilities.isLargeScreen(any())).thenReturn(true);
+        mNavigationBarController.mIsLargeScreen = true;
         when(mTaskbarDelegate.isInitialized()).thenReturn(true);
         mNavigationBarController.onConfigChanged(configuration);
         verify(mTaskbarDelegate, times(1)).onConfigurationChanged(configuration);
     }
 
     @Test
-    public void testConfigurationChangeFolding_taskbarInitialized() {
+    public void testShouldRenderTaskbar_taskbarNotRenderedOnPhone() {
+        mNavigationBarController.mIsLargeScreen = false;
+        mNavigationBarController.mIsPhone = true;
+        assertFalse(mNavigationBarController.supportsTaskbar());
+    }
+
+    @Test
+    public void testShouldRenderTaskbar_taskbarRenderedOnTabletOrUnfolded() {
+        mNavigationBarController.mIsLargeScreen = true;
+        mNavigationBarController.mIsPhone = false;
+        assertTrue(mNavigationBarController.supportsTaskbar());
+    }
+
+    @Test
+    public void testShouldRenderTaskbar_taskbarRenderedInFoldedState() {
         assumeTrue(enableTaskbarNavbarUnification());
 
-        Configuration configuration = mContext.getResources().getConfiguration();
-        when(Utilities.isLargeScreen(any())).thenReturn(false);
-        when(mTaskbarDelegate.isInitialized()).thenReturn(true);
-        mNavigationBarController.onConfigChanged(configuration);
-        verify(mTaskbarDelegate, times(1)).onConfigurationChanged(configuration);
+        mNavigationBarController.mIsLargeScreen = false;
+        mNavigationBarController.mIsPhone = false;
+        assertTrue(mNavigationBarController.supportsTaskbar());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index ccc9dc0..8a48fe1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -50,8 +50,8 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.SbnBuilder;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -280,6 +280,66 @@
     }
 
     @Test
+    public void testIsNotificationVisibilityPrivate_true() {
+        assertTrue(mEntry.isNotificationVisibilityPrivate());
+    }
+
+    @Test
+    public void testIsNotificationVisibilityPrivate_visibilityPublic_false() {
+        Notification.Builder notification = new Notification.Builder(mContext, "")
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+
+        NotificationEntry entry = new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_NAME)
+                .setOpPkg(TEST_PACKAGE_NAME)
+                .setUid(TEST_UID)
+                .setChannel(mChannel)
+                .setId(mId++)
+                .setNotification(notification.build())
+                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+                .build();
+
+        assertFalse(entry.isNotificationVisibilityPrivate());
+    }
+
+    @Test
+    public void testIsChannelVisibilityPrivate_true() {
+        assertTrue(mEntry.isChannelVisibilityPrivate());
+    }
+
+    @Test
+    public void testIsChannelVisibilityPrivate_visibilityPublic_false() {
+        NotificationChannel channel =
+                new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
+        channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
+        StatusBarNotification sbn = new SbnBuilder().build();
+        Ranking ranking = new RankingBuilder()
+                .setChannel(channel)
+                .setKey(sbn.getKey())
+                .build();
+        NotificationEntry entry =
+                new NotificationEntry(sbn, ranking, mClock.uptimeMillis());
+
+        assertFalse(entry.isChannelVisibilityPrivate());
+    }
+
+    @Test
+    public void testIsChannelVisibilityPrivate_entryHasNoChannel_false() {
+        StatusBarNotification sbn = new SbnBuilder().build();
+        Ranking ranking = new RankingBuilder()
+                .setChannel(null)
+                .setKey(sbn.getKey())
+                .build();
+        NotificationEntry entry =
+                new NotificationEntry(sbn, ranking, mClock.uptimeMillis());
+
+        assertFalse(entry.isChannelVisibilityPrivate());
+    }
+
+    @Test
     public void notificationDataEntry_testIsLastMessageFromReply() {
         Person.Builder person = new Person.Builder()
                 .setName("name")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
index 1dac642..a2af38f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
@@ -19,17 +19,24 @@
 import android.app.ActivityOptions
 import android.app.IActivityManager
 import android.app.Notification
+import android.app.Notification.FLAG_FOREGROUND_SERVICE
+import android.app.Notification.VISIBILITY_PRIVATE
+import android.app.Notification.VISIBILITY_PUBLIC
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
 import android.media.projection.MediaProjectionInfo
 import android.media.projection.MediaProjectionManager
 import android.platform.test.annotations.EnableFlags
 import android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS
-import android.service.notification.StatusBarNotification
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
 import com.android.server.notification.Flags
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.RankingBuilder
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.concurrency.mockExecutorHandler
 import com.android.systemui.util.mockito.whenever
@@ -316,6 +323,25 @@
 
         assertFalse(controller.shouldProtectNotification(notificationEntry))
     }
+    @Test
+    fun shouldProtectNotification_projectionActive_publicNotification_false() {
+        mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+        // App marked notification visibility as public
+        val notificationEntry = setupPublicNotificationEntry(TEST_PROJECTION_PACKAGE_NAME)
+
+        assertFalse(controller.shouldProtectNotification(notificationEntry))
+    }
+
+    @Test
+    fun shouldProtectNotification_projectionActive_publicNotificationUserChannelOverride_true() {
+        mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+        val notificationEntry =
+            setupPublicNotificationEntryWithUserOverriddenChannel(TEST_PROJECTION_PACKAGE_NAME)
+
+        assertTrue(controller.shouldProtectNotification(notificationEntry))
+    }
 
     private fun setDisabledViaDeveloperOption() {
         globalSettings.putInt(DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1)
@@ -336,21 +362,50 @@
 
     private fun setupNotificationEntry(
         packageName: String,
-        isFgs: Boolean = false
+        isFgs: Boolean = false,
+        overrideVisibility: Boolean = false,
+        overrideChannelVisibility: Boolean = false,
     ): NotificationEntry {
-        val notificationEntry = mock(NotificationEntry::class.java)
-        val sbn = mock(StatusBarNotification::class.java)
-        val notification = mock(Notification::class.java)
-        whenever(notificationEntry.sbn).thenReturn(sbn)
-        whenever(sbn.packageName).thenReturn(packageName)
-        whenever(sbn.notification).thenReturn(notification)
-        whenever(notification.isFgsOrUij).thenReturn(isFgs)
-
+        val notification = Notification()
+        if (isFgs) {
+            notification.flags = notification.flags or FLAG_FOREGROUND_SERVICE
+        }
+        if (overrideVisibility) {
+            // Developer has marked notification as public
+            notification.visibility = VISIBILITY_PUBLIC
+        }
+        val notificationEntry =
+            NotificationEntryBuilder().setNotification(notification).setPkg(packageName).build()
+        val channel = NotificationChannel("1", "1", IMPORTANCE_HIGH)
+        if (overrideChannelVisibility) {
+            // User doesn't allow private notifications at the channel level
+            channel.lockscreenVisibility = VISIBILITY_PRIVATE
+        }
+        notificationEntry.setRanking(
+            RankingBuilder(notificationEntry.ranking)
+                .setChannel(channel)
+                .setVisibilityOverride(VISIBILITY_NO_OVERRIDE)
+                .build()
+        )
         return notificationEntry
     }
 
     private fun setupFgsNotificationEntry(packageName: String): NotificationEntry {
-        return setupNotificationEntry(packageName, /* isFgs= */ true)
+        return setupNotificationEntry(packageName, isFgs = true)
+    }
+
+    private fun setupPublicNotificationEntry(packageName: String): NotificationEntry {
+        return setupNotificationEntry(packageName, overrideVisibility = true)
+    }
+
+    private fun setupPublicNotificationEntryWithUserOverriddenChannel(
+        packageName: String
+    ): NotificationEntry {
+        return setupNotificationEntry(
+            packageName,
+            overrideVisibility = true,
+            overrideChannelVisibility = true
+        )
     }
 
     companion object {
diff --git a/ravenwood/run-ravenwood-tests.sh b/ravenwood/run-ravenwood-tests.sh
index 3f4b8a7..259aa70 100755
--- a/ravenwood/run-ravenwood-tests.sh
+++ b/ravenwood/run-ravenwood-tests.sh
@@ -13,10 +13,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Run all the ravenwood tests.
+# Run all the ravenwood tests + hoststubgen unit tests.
+
+all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test"
 
 # "echo" is to remove the newlines
-all_tests=$(echo $(${0%/*}/list-ravenwood-tests.sh) )
+all_tests="$all_tests $(echo $(${0%/*}/list-ravenwood-tests.sh) )"
 
 echo "Running tests: $all_tests"
 atest $all_tests
diff --git a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
new file mode 100644
index 0000000..3312be2
--- /dev/null
+++ b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.adaptiveauth;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.hardware.biometrics.AuthenticationStateListener;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricSourceType;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
+import com.android.internal.widget.LockSettingsStateListener;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.pm.UserManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public class AdaptiveAuthService extends SystemService {
+    private static final String TAG = "AdaptiveAuthService";
+    private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG);
+
+    @VisibleForTesting
+    static final int MAX_ALLOWED_FAILED_AUTH_ATTEMPTS = 5;
+    private static final int MSG_REPORT_PRIMARY_AUTH_ATTEMPT = 1;
+    private static final int MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT = 2;
+    private static final int AUTH_SUCCESS = 1;
+    private static final int AUTH_FAILURE = 0;
+
+    private final LockPatternUtils mLockPatternUtils;
+    private final LockSettingsInternal mLockSettings;
+    private final BiometricManager mBiometricManager;
+    private final KeyguardManager mKeyguardManager;
+    private final PowerManager mPowerManager;
+    private final WindowManagerInternal mWindowManager;
+    private final UserManagerInternal mUserManager;
+    @VisibleForTesting
+    final SparseIntArray mFailedAttemptsForUser = new SparseIntArray();
+
+    public AdaptiveAuthService(Context context) {
+        this(context, new LockPatternUtils(context));
+    }
+
+    @VisibleForTesting
+    public AdaptiveAuthService(Context context, LockPatternUtils lockPatternUtils) {
+        super(context);
+        mLockPatternUtils = lockPatternUtils;
+        mLockSettings = Objects.requireNonNull(
+                LocalServices.getService(LockSettingsInternal.class));
+        mBiometricManager = Objects.requireNonNull(
+                context.getSystemService(BiometricManager.class));
+        mKeyguardManager = Objects.requireNonNull(context.getSystemService(KeyguardManager.class));
+        mPowerManager = Objects.requireNonNull(context.getSystemService(PowerManager.class));
+        mWindowManager = Objects.requireNonNull(
+                LocalServices.getService(WindowManagerInternal.class));
+        mUserManager = Objects.requireNonNull(LocalServices.getService(UserManagerInternal.class));
+    }
+
+    @Override
+    public void onStart() {}
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            init();
+        }
+    }
+
+    @VisibleForTesting
+    void init() {
+        mLockSettings.registerLockSettingsStateListener(mLockSettingsStateListener);
+        mBiometricManager.registerAuthenticationStateListener(mAuthenticationStateListener);
+    }
+
+    private final LockSettingsStateListener mLockSettingsStateListener =
+            new LockSettingsStateListener() {
+                @Override
+                public void onAuthenticationSucceeded(int userId) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "LockSettingsStateListener#onAuthenticationSucceeded");
+                    }
+                    mHandler.obtainMessage(MSG_REPORT_PRIMARY_AUTH_ATTEMPT, AUTH_SUCCESS, userId)
+                            .sendToTarget();
+                }
+
+                @Override
+                public void onAuthenticationFailed(int userId) {
+                    Slog.i(TAG, "LockSettingsStateListener#onAuthenticationFailed");
+                    mHandler.obtainMessage(MSG_REPORT_PRIMARY_AUTH_ATTEMPT, AUTH_FAILURE, userId)
+                            .sendToTarget();
+                }
+            };
+
+    private final AuthenticationStateListener mAuthenticationStateListener =
+            new AuthenticationStateListener.Stub() {
+                @Override
+                public void onAuthenticationStarted(int requestReason) {}
+
+                @Override
+                public void onAuthenticationStopped() {}
+
+                @Override
+                public void onAuthenticationSucceeded(int requestReason, int userId) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "AuthenticationStateListener#onAuthenticationSucceeded");
+                    }
+                    mHandler.obtainMessage(MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT, AUTH_SUCCESS, userId)
+                            .sendToTarget();
+                }
+
+                @Override
+                public void onAuthenticationFailed(int requestReason, int userId) {
+                    Slog.i(TAG, "AuthenticationStateListener#onAuthenticationFailed");
+                    mHandler.obtainMessage(MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT, AUTH_FAILURE, userId)
+                            .sendToTarget();
+                }
+
+                @Override
+                public void onAuthenticationAcquired(BiometricSourceType biometricSourceType,
+                        int requestReason, int acquiredInfo) {}
+            };
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_REPORT_PRIMARY_AUTH_ATTEMPT:
+                    handleReportPrimaryAuthAttempt(msg.arg1 != AUTH_FAILURE, msg.arg2);
+                    break;
+                case MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT:
+                    handleReportBiometricAuthAttempt(msg.arg1 != AUTH_FAILURE, msg.arg2);
+                    break;
+            }
+        }
+    };
+
+    private void handleReportPrimaryAuthAttempt(boolean success, int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "handleReportPrimaryAuthAttempt: success=" + success
+                    + ", userId=" + userId);
+        }
+        reportAuthAttempt(success, userId);
+    }
+
+    private void handleReportBiometricAuthAttempt(boolean success, int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "handleReportBiometricAuthAttempt: success=" + success
+                    + ", userId=" + userId);
+        }
+        reportAuthAttempt(success, userId);
+    }
+
+    private void reportAuthAttempt(boolean success, int userId) {
+        if (success) {
+            // Deleting the entry effectively resets the counter of failed attempts for the user
+            mFailedAttemptsForUser.delete(userId);
+            return;
+        }
+
+        final int numFailedAttempts = mFailedAttemptsForUser.get(userId, 0) + 1;
+        Slog.i(TAG, "reportAuthAttempt: numFailedAttempts=" + numFailedAttempts
+                + ", userId=" + userId);
+        mFailedAttemptsForUser.put(userId, numFailedAttempts);
+
+        // Don't lock again if the device is already locked and if Keyguard is already showing and
+        // isn't trivially dismissible
+        if (mKeyguardManager.isDeviceLocked(userId) && mKeyguardManager.isKeyguardLocked()) {
+            Slog.d(TAG, "Not locking the device because the device is already locked.");
+            return;
+        }
+
+        if (numFailedAttempts < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS) {
+            Slog.d(TAG, "Not locking the device because the number of failed attempts is below"
+                    + " the threshold.");
+            return;
+        }
+
+        //TODO: additionally consider the trust signal before locking device
+        lockDevice(userId);
+    }
+
+    /**
+     * Locks the device and requires primary auth or biometric auth for unlocking
+     */
+    private void lockDevice(int userId) {
+        // Require either primary auth or biometric auth to unlock the device again. Keyguard and
+        // bouncer will also check the StrongAuthFlag for the user to display correct strings for
+        // explaining why the device is locked
+        mLockPatternUtils.requireStrongAuth(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST, userId);
+
+        // If userId is a profile that has a different parent userId (regardless of its profile
+        // type, or whether it's a profile with unified challenges or not), its parent userId that
+        // owns the Keyguard will also be locked
+        final int parentUserId = mUserManager.getProfileParentId(userId);
+        Slog.i(TAG, "lockDevice: userId=" + userId + ", parentUserId=" + parentUserId);
+        if (parentUserId != userId) {
+            mLockPatternUtils.requireStrongAuth(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST,
+                    parentUserId);
+        }
+
+        // Power off the display
+        mPowerManager.goToSleep(SystemClock.uptimeMillis());
+
+        // Lock the device
+        mWindowManager.lockNow();
+    }
+}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 7d82f0c..df46e5d 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL_IMPLICIT;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_BFSL;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
@@ -67,7 +68,10 @@
 import static android.content.Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL;
+import static android.media.audio.Flags.foregroundAudioControl;
 import static android.os.Process.SCHED_OTHER;
 import static android.os.Process.THREAD_GROUP_BACKGROUND;
 import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -2266,6 +2270,15 @@
                             (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
                                     != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
 
+                    if (foregroundAudioControl()) { // flag check
+                        final int fgsAudioType = FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
+                                | FOREGROUND_SERVICE_TYPE_CAMERA
+                                | FOREGROUND_SERVICE_TYPE_MICROPHONE
+                                | FOREGROUND_SERVICE_TYPE_PHONE_CALL;
+                        capabilityFromFGS |= (psr.getForegroundServiceTypes() & fgsAudioType) != 0
+                                ? PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL : 0;
+                    }
+
                     final boolean enabled = state.getCachedCompatChange(
                             CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY);
                     if (enabled) {
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index f85b03e..1bf779a 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -722,14 +722,8 @@
         performNewUpdateOomAdjLSP(oomAdjReason, topApp, targetProcesses, activeUids,
                 fullUpdate, now, UNKNOWN_ADJ);
 
-        if (fullUpdate) {
-            assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
-        } else {
-            activeProcesses.clear();
-            activeProcesses.addAll(targetProcesses);
-            assignCachedAdjIfNecessary(activeProcesses);
-            activeProcesses.clear();
-        }
+        // TODO: b/319163103 - optimize cache adj assignment to not require the whole lru list.
+        assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
         postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime);
         targetProcesses.clear();
 
@@ -996,11 +990,11 @@
                             && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
                     || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
                             && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
-                            && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
+                            && service.mState.getCurProcState() <= PROCESS_STATE_TOP)
+                    || (service.isSdkSandbox && cr.binding.attributedClient != null)) {
                 continue;
             }
 
-
             computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
                     oomAdjReason, cachedAdj, false, false);
         }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index d23d9fb..9883f09 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1678,7 +1678,11 @@
                 final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(j);
                 for (int k = clist.size() - 1; k >= 0; k--) {
                     final ConnectionRecord cr = clist.get(k);
-                    consumer.accept(cr.binding.client);
+                    if (isSdkSandbox && cr.binding.attributedClient != null) {
+                        consumer.accept(cr.binding.attributedClient);
+                    } else {
+                        consumer.accept(cr.binding.client);
+                    }
                 }
             }
         }
@@ -1689,25 +1693,5 @@
                 consumer.accept(conn.client);
             }
         }
-        // If this process is a sandbox itself, also add the app on whose behalf
-        // its running
-        if (isSdkSandbox) {
-            for (int is = mServices.numberOfRunningServices() - 1; is >= 0; is--) {
-                ServiceRecord s = mServices.getRunningServiceAt(is);
-                ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
-                        s.getConnections();
-                for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) {
-                    ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
-                    for (int i = clist.size() - 1; i >= 0; i--) {
-                        ConnectionRecord cr = clist.get(i);
-                        ProcessRecord attributedApp = cr.binding.attributedClient;
-                        if (attributedApp == null || attributedApp == this) {
-                            continue;
-                        }
-                        consumer.accept(attributedApp);
-                    }
-                }
-            }
-        }
     }
 }
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 57d233e..562beaf 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -205,10 +205,10 @@
     }
 
     /**
-     * Returns the FGS typps, but it doesn't tell if the types include "NONE" or not, so
-     * do not use it outside of this class.
+     * Returns the FGS types, but it doesn't tell if the types include "NONE" or not, use
+     * {@link #hasForegroundServices()}
      */
-    private int getForegroundServiceTypes() {
+    int getForegroundServiceTypes() {
         return mHasForegroundServices ? mFgServiceTypes : 0;
     }
 
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 145b213..fca1199 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -166,7 +166,6 @@
 import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
-import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemServiceManager;
 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 import com.android.server.pm.PackageList;
@@ -659,11 +658,11 @@
             return attributedOp;
         }
 
-        @NonNull OpEntry createEntryLocked() {
+        @NonNull OpEntry createEntryLocked(String persistentDeviceId) {
             // TODO(b/308201969): Update this method when we introduce disk persistence of events
             // for accesses on external devices.
             final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
-                    PERSISTENT_DEVICE_ID_DEFAULT);
+                    persistentDeviceId);
             final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
                     new ArrayMap<>(attributedOps.size());
             for (int i = 0; i < attributedOps.size(); i++) {
@@ -1038,7 +1037,7 @@
                                 new Ops(pkgName, uidState));
                     }
 
-                    createSandboxUidStateIfNotExistsForAppLocked(uid);
+                    createSandboxUidStateIfNotExistsForAppLocked(uid, null);
                 }
             } else if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
                 synchronized (AppOpsService.this) {
@@ -1050,69 +1049,8 @@
                     return;
                 }
 
-                ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
-                ArraySet<String> attributionTags = new ArraySet<>();
-                attributionTags.add(null);
-                if (pkg.getAttributions() != null) {
-                    int numAttributions = pkg.getAttributions().size();
-                    for (int attributionNum = 0; attributionNum < numAttributions;
-                            attributionNum++) {
-                        ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
-                        attributionTags.add(attribution.getTag());
-
-                        int numInheritFrom = attribution.getInheritFrom().size();
-                        for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
-                                inheritFromNum++) {
-                            dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
-                                    attribution.getTag());
-                        }
-                    }
-                }
-
                 synchronized (AppOpsService.this) {
-                    UidState uidState = mUidStates.get(uid);
-                    if (uidState == null) {
-                        return;
-                    }
-
-                    Ops ops = uidState.pkgOps.get(pkgName);
-                    if (ops == null) {
-                        return;
-                    }
-
-                    // Reset cached package properties to re-initialize when needed
-                    ops.bypass = null;
-                    ops.knownAttributionTags.clear();
-
-                    // Merge data collected for removed attributions into their successor
-                    // attributions
-                    int numOps = ops.size();
-                    for (int opNum = 0; opNum < numOps; opNum++) {
-                        Op op = ops.valueAt(opNum);
-                        for (int deviceIndex = op.mDeviceAttributedOps.size() - 1; deviceIndex >= 0;
-                                deviceIndex--) {
-                            ArrayMap<String, AttributedOp> attributedOps =
-                                    op.mDeviceAttributedOps.valueAt(deviceIndex);
-                            for (int tagIndex = attributedOps.size() - 1; tagIndex >= 0;
-                                    tagIndex--) {
-                                String tag = attributedOps.keyAt(tagIndex);
-                                if (attributionTags.contains(tag)) {
-                                    // attribution still exist after upgrade
-                                    continue;
-                                }
-
-                                String newAttributionTag = dstAttributionTags.get(tag);
-
-                                AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
-                                        newAttributionTag,
-                                        op.mDeviceAttributedOps.keyAt(deviceIndex));
-                                newAttributedOp.add(attributedOps.get(tag));
-                                attributedOps.remove(tag);
-
-                                scheduleFastWriteLocked();
-                            }
-                        }
-                    }
+                    refreshAttributionsLocked(pkg, uid);
                 }
             }
         }
@@ -1136,41 +1074,6 @@
         mContext.registerReceiverAsUser(mOnPackageUpdatedReceiver, UserHandle.ALL,
                 packageUpdateFilter, null, null);
 
-        synchronized (this) {
-            for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
-                int uid = mUidStates.keyAt(uidNum);
-                UidState uidState = mUidStates.valueAt(uidNum);
-
-                String[] pkgsInUid = getPackagesForUid(uidState.uid);
-                if (ArrayUtils.isEmpty(pkgsInUid) && uid >= Process.FIRST_APPLICATION_UID) {
-                    uidState.clear();
-                    mUidStates.removeAt(uidNum);
-                    scheduleFastWriteLocked();
-                    continue;
-                }
-
-                ArrayMap<String, Ops> pkgs = uidState.pkgOps;
-
-                int numPkgs = pkgs.size();
-                for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
-                    String pkg = pkgs.keyAt(pkgNum);
-
-                    String action;
-                    if (!ArrayUtils.contains(pkgsInUid, pkg)) {
-                        action = ACTION_PACKAGE_REMOVED;
-                    } else {
-                        action = Intent.ACTION_PACKAGE_REPLACED;
-                    }
-
-                    SystemServerInitThreadPool.submit(
-                            () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
-                                    .setData(Uri.fromParts("package", pkg, null))
-                                    .putExtra(Intent.EXTRA_UID, uid)),
-                            "Update app-ops uidState in case package " + pkg + " changed");
-                }
-            }
-        }
-
         prepareInternalCallbacks();
 
         final IntentFilter packageSuspendFilter = new IntentFilter();
@@ -1258,20 +1161,27 @@
     void initializeUidStates() {
         UserManagerInternal umi = getUserManagerInternal();
         synchronized (this) {
+            SparseBooleanArray knownUids = new SparseBooleanArray();
+
+            for (int uid : NON_PACKAGE_UIDS) {
+                if (!mUidStates.contains(uid)) {
+                    mUidStates.put(uid, new UidState(uid));
+                }
+                knownUids.put(uid, true);
+            }
+
             int[] userIds = umi.getUserIds();
             try (PackageManagerLocal.UnfilteredSnapshot snapshot =
                          getPackageManagerLocal().withUnfilteredSnapshot()) {
                 Map<String, PackageState> packageStates = snapshot.getPackageStates();
                 for (int i = 0; i < userIds.length; i++) {
                     int userId = userIds[i];
-                    initializeUserUidStatesLocked(userId, packageStates);
+                    initializeUserUidStatesLocked(userId, packageStates, knownUids);
                 }
-            }
 
-            for (int uid : NON_PACKAGE_UIDS) {
-                mUidStates.put(uid, new UidState(uid));
+                trimUidStatesLocked(knownUids, packageStates);
+                mUidStatesInitialized = true;
             }
-            mUidStatesInitialized = true;
         }
     }
 
@@ -1279,26 +1189,34 @@
         synchronized (this) {
             try (PackageManagerLocal.UnfilteredSnapshot snapshot =
                     getPackageManagerLocal().withUnfilteredSnapshot()) {
-                initializeUserUidStatesLocked(userId, snapshot.getPackageStates());
+                initializeUserUidStatesLocked(userId, snapshot.getPackageStates(), null);
             }
         }
     }
 
     private void initializeUserUidStatesLocked(int userId, Map<String,
-            PackageState> packageStates) {
+            PackageState> packageStates, SparseBooleanArray knownUids) {
         for (Map.Entry<String, PackageState> entry : packageStates.entrySet()) {
-            int appId = entry.getValue().getAppId();
+            PackageState packageState = entry.getValue();
+            if (packageState.isApex()) {
+                continue;
+            }
+            int appId = packageState.getAppId();
             String packageName = entry.getKey();
 
-            initializePackageUidStateLocked(userId, appId, packageName);
+            initializePackageUidStateLocked(userId, appId, packageName, knownUids);
         }
     }
 
     /*
       Be careful not to clear any existing data; only want to add objects that don't already exist.
      */
-    private void initializePackageUidStateLocked(int userId, int appId, String packageName) {
+    private void initializePackageUidStateLocked(int userId, int appId, String packageName,
+            SparseBooleanArray knownUids) {
         int uid = UserHandle.getUid(userId, appId);
+        if (knownUids != null) {
+            knownUids.put(uid, true);
+        }
         UidState uidState = getUidStateLocked(uid, true);
         Ops ops = uidState.pkgOps.get(packageName);
         if (ops == null) {
@@ -1316,7 +1234,105 @@
             }
         }
 
-        createSandboxUidStateIfNotExistsForAppLocked(uid);
+        createSandboxUidStateIfNotExistsForAppLocked(uid, knownUids);
+    }
+
+    private void trimUidStatesLocked(SparseBooleanArray knownUids,
+            Map<String, PackageState> packageStates) {
+        synchronized (this) {
+            // Remove what may have been added during persistence parsing
+            for (int i = mUidStates.size() - 1; i >= 0; i--) {
+                int uid = mUidStates.keyAt(i);
+                if (knownUids.get(uid, false)) {
+                    if (uid >= Process.FIRST_APPLICATION_UID) {
+                        ArrayMap<String, Ops> pkgOps = mUidStates.valueAt(i).pkgOps;
+                        for (int j = 0; j < pkgOps.size(); j++) {
+                            String pkgName = pkgOps.keyAt(j);
+                            if (!packageStates.containsKey(pkgName)) {
+                                pkgOps.removeAt(j);
+                                continue;
+                            }
+                            AndroidPackage pkg = packageStates.get(pkgName).getAndroidPackage();
+                            if (pkg != null) {
+                                refreshAttributionsLocked(pkg, uid);
+                            }
+                        }
+                        if (pkgOps.isEmpty()) {
+                            mUidStates.remove(i);
+                        }
+                    }
+                } else {
+                    mUidStates.removeAt(i);
+                }
+            }
+        }
+    }
+
+    @GuardedBy("this")
+    private void refreshAttributionsLocked(AndroidPackage pkg, int uid) {
+        String pkgName = pkg.getPackageName();
+        ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
+        ArraySet<String> attributionTags = new ArraySet<>();
+        attributionTags.add(null);
+        if (pkg.getAttributions() != null) {
+            int numAttributions = pkg.getAttributions().size();
+            for (int attributionNum = 0; attributionNum < numAttributions;
+                    attributionNum++) {
+                ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
+                attributionTags.add(attribution.getTag());
+
+                int numInheritFrom = attribution.getInheritFrom().size();
+                for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
+                        inheritFromNum++) {
+                    dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
+                            attribution.getTag());
+                }
+            }
+        }
+
+        UidState uidState = mUidStates.get(uid);
+        if (uidState == null) {
+            return;
+        }
+
+        Ops ops = uidState.pkgOps.get(pkgName);
+        if (ops == null) {
+            return;
+        }
+
+        // Reset cached package properties to re-initialize when needed
+        ops.bypass = null;
+        ops.knownAttributionTags.clear();
+
+        // Merge data collected for removed attributions into their successor
+        // attributions
+        int numOps = ops.size();
+        for (int opNum = 0; opNum < numOps; opNum++) {
+            Op op = ops.valueAt(opNum);
+            for (int deviceIndex = op.mDeviceAttributedOps.size() - 1; deviceIndex >= 0;
+                    deviceIndex--) {
+                ArrayMap<String, AttributedOp> attributedOps =
+                        op.mDeviceAttributedOps.valueAt(deviceIndex);
+                for (int tagIndex = attributedOps.size() - 1; tagIndex >= 0;
+                        tagIndex--) {
+                    String tag = attributedOps.keyAt(tagIndex);
+                    if (attributionTags.contains(tag)) {
+                        // attribution still exist after upgrade
+                        continue;
+                    }
+
+                    String newAttributionTag = dstAttributionTags.get(tag);
+
+                    AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
+                            newAttributionTag,
+                            op.mDeviceAttributedOps.keyAt(deviceIndex));
+                    newAttributedOp.add(attributedOps.get(tag));
+                    attributedOps.remove(tag);
+
+                    scheduleFastWriteLocked();
+                }
+            }
+        }
     }
 
     /**
@@ -1534,13 +1550,14 @@
         mHistoricalRegistry.shutdown();
     }
 
-    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
+    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops,
+            String persistentDeviceId) {
         ArrayList<AppOpsManager.OpEntry> resOps = null;
         if (ops == null) {
             resOps = new ArrayList<>();
             for (int j=0; j<pkgOps.size(); j++) {
                 Op curOp = pkgOps.valueAt(j);
-                resOps.add(getOpEntryForResult(curOp));
+                resOps.add(getOpEntryForResult(curOp, persistentDeviceId));
             }
         } else {
             for (int j=0; j<ops.length; j++) {
@@ -1549,7 +1566,7 @@
                     if (resOps == null) {
                         resOps = new ArrayList<>();
                     }
-                    resOps.add(getOpEntryForResult(curOp));
+                    resOps.add(getOpEntryForResult(curOp, persistentDeviceId));
                 }
             }
         }
@@ -1593,16 +1610,23 @@
         return resOps;
     }
 
-    private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op) {
-        return op.createEntryLocked();
+    private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, String persistentDeviceId) {
+        return op.createEntryLocked(persistentDeviceId);
     }
 
     @Override
     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
+        return getPackagesForOpsForDevice(ops, PERSISTENT_DEVICE_ID_DEFAULT);
+    }
+
+    @Override
+    public List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(int[] ops,
+            @NonNull String persistentDeviceId) {
         final int callingUid = Binder.getCallingUid();
         final boolean hasAllPackageAccess = mContext.checkPermission(
                 Manifest.permission.GET_APP_OPS_STATS, Binder.getCallingPid(),
                 Binder.getCallingUid(), null) == PackageManager.PERMISSION_GRANTED;
+
         ArrayList<AppOpsManager.PackageOps> res = null;
         synchronized (this) {
             final int uidStateCount = mUidStates.size();
@@ -1611,21 +1635,24 @@
                 if (uidState.pkgOps.isEmpty()) {
                     continue;
                 }
+                // Caller can always see their packages and with a permission all.
+                if (!hasAllPackageAccess && callingUid != uidState.uid) {
+                    continue;
+                }
+
                 ArrayMap<String, Ops> packages = uidState.pkgOps;
                 final int packageCount = packages.size();
                 for (int j = 0; j < packageCount; j++) {
                     Ops pkgOps = packages.valueAt(j);
-                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
+                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops,
+                            persistentDeviceId);
                     if (resOps != null) {
                         if (res == null) {
                             res = new ArrayList<>();
                         }
                         AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
                                 pkgOps.packageName, pkgOps.uidState.uid, resOps);
-                        // Caller can always see their packages and with a permission all.
-                        if (hasAllPackageAccess || callingUid == pkgOps.uidState.uid) {
-                            res.add(resPackage);
-                        }
+                        res.add(resPackage);
                     }
                 }
             }
@@ -1647,7 +1674,8 @@
             if (pkgOps == null) {
                 return null;
             }
-            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
+            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops,
+                    PERSISTENT_DEVICE_ID_DEFAULT);
             if (resOps == null || resOps.size() == 0) {
                 return null;
             }
@@ -4251,8 +4279,15 @@
         return uidState;
     }
 
-    private void createSandboxUidStateIfNotExistsForAppLocked(int uid) {
+    private void createSandboxUidStateIfNotExistsForAppLocked(int uid,
+            SparseBooleanArray knownUids) {
+        if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
+            return;
+        }
         final int sandboxUid = Process.toSdkSandboxUid(uid);
+        if (knownUids != null) {
+            knownUids.put(sandboxUid, true);
+        }
         getUidStateLocked(sandboxUid, true);
     }
 
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index 23a384f..bc6ef20 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.appop;
 
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
@@ -30,6 +31,7 @@
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
 import static android.app.AppOpsManager.UID_STATE_TOP;
@@ -139,7 +141,6 @@
     }
 
     private int evalModeInternal(int uid, int code, int uidState, int uidCapability) {
-
         if (getUidAppWidgetVisible(uid) || mActivityManagerInternal.isPendingTopUid(uid)
                 || mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid)) {
             return MODE_ALLOWED;
@@ -173,6 +174,8 @@
             case OP_RECORD_AUDIO:
             case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
                 return PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+            case OP_TAKE_AUDIO_FOCUS:
+                return PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
             default:
                 return PROCESS_CAPABILITY_NONE;
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c59f4f7..559a1d6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -34,6 +34,7 @@
 import static android.media.audio.Flags.automaticBtDeviceType;
 import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency;
 import static android.media.audio.Flags.focusFreezeTestApi;
+import static android.media.audio.Flags.foregroundAudioControl;
 import static android.media.audiopolicy.Flags.enableFadeManagerConfiguration;
 import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.INVALID_UID;
@@ -1356,7 +1357,8 @@
 
         mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler);
 
-        mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive());
+        mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive(), mAppOps,
+                context.getPackageManager());
     }
 
     private void initVolumeStreamStates() {
@@ -4517,7 +4519,8 @@
     }
 
     private void dumpFlags(PrintWriter pw) {
-        pw.println("\nFun with Flags: ");
+
+        pw.println("\nFun with Flags:");
         pw.println("\tandroid.media.audio.autoPublicVolumeApiHardening:"
                 + autoPublicVolumeApiHardening());
         pw.println("\tandroid.media.audio.Flags.automaticBtDeviceType:"
@@ -4528,8 +4531,8 @@
                 + focusFreezeTestApi());
         pw.println("\tcom.android.media.audio.disablePrescaleAbsoluteVolume:"
                 + disablePrescaleAbsoluteVolume());
-        pw.println("\tandroid.media.audiopolicy.enableFadeManagerConfiguration:"
-                + enableFadeManagerConfiguration());
+        pw.println("\tandroid.media.audio.foregroundAudioControl:"
+                + foregroundAudioControl());
     }
 
     private void dumpAudioMode(PrintWriter pw) {
@@ -10175,10 +10178,38 @@
                     .record();
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
+
+        // does caller have system privileges to bypass HardeningEnforcer
+        boolean permissionOverridesCheck = false;
+        if ((mContext.checkCallingOrSelfPermission(
+                Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+                == PackageManager.PERMISSION_GRANTED)
+                || (mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
+                == PackageManager.PERMISSION_GRANTED)) {
+            permissionOverridesCheck = true;
+        } else if (uid < UserHandle.AID_APP_START) {
+            permissionOverridesCheck = true;
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (!permissionOverridesCheck && mHardeningEnforcer.blockFocusMethod(uid,
+                    HardeningEnforcer.METHOD_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS,
+                    clientId, durationHint, callingPackageName)) {
+                final String reason = "Audio focus request blocked by hardening";
+                Log.w(TAG, reason);
+                mmi.set(MediaMetrics.Property.EARLY_RETURN, reason).record();
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
         mmi.record();
         return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
                 clientId, callingPackageName, attributionTag, flags, sdk,
-                forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/);
+                forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/,
+                permissionOverridesCheck);
     }
 
     /** see {@link AudioManager#requestAudioFocusForTest(AudioFocusRequest, String, int, int)} */
@@ -10195,7 +10226,7 @@
         }
         return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
                 clientId, callingPackageName, null, flags,
-                sdk, false /*forceDuck*/, fakeUid);
+                sdk, false /*forceDuck*/, fakeUid, true /*permissionOverridesCheck*/);
     }
 
     public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa,
@@ -11639,6 +11670,7 @@
             pw.println("\nMessage handler is null");
         }
         dumpFlags(pw);
+        mHardeningEnforcer.dump(pw);
         mMediaFocusControl.dump(pw);
         dumpStreamStates(pw);
         dumpVolumeGroups(pw);
diff --git a/services/core/java/com/android/server/audio/HardeningEnforcer.java b/services/core/java/com/android/server/audio/HardeningEnforcer.java
index 4ceb83b2..409ed17 100644
--- a/services/core/java/com/android/server/audio/HardeningEnforcer.java
+++ b/services/core/java/com/android/server/audio/HardeningEnforcer.java
@@ -18,13 +18,21 @@
 import static android.media.audio.Flags.autoPublicVolumeApiHardening;
 
 import android.Manifest;
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.AudioFocusRequest;
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.UserHandle;
 import android.text.TextUtils;
-import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.utils.EventLogger;
+
+import java.io.PrintWriter;
 
 /**
  * Class to encapsulate all audio API hardening operations
@@ -32,10 +40,19 @@
 public class HardeningEnforcer {
 
     private static final String TAG = "AS.HardeningEnforcer";
+    private static final boolean DEBUG = false;
+    private static final int LOG_NB_EVENTS = 20;
 
     final Context mContext;
+    final AppOpsManager mAppOps;
     final boolean mIsAutomotive;
 
+    final ActivityManager mActivityManager;
+    final PackageManager mPackageManager;
+
+    final EventLogger mEventLogger = new EventLogger(LOG_NB_EVENTS,
+            "Hardening enforcement");
+
     /**
      * Matches calls from {@link AudioManager#setStreamVolume(int, int, int)}
      */
@@ -56,10 +73,24 @@
      * Matches calls from {@link AudioManager#setRingerMode(int)}
      */
     public static final int METHOD_AUDIO_MANAGER_SET_RINGER_MODE = 200;
+    /**
+     * Matches calls from {@link AudioManager#requestAudioFocus(AudioFocusRequest)}
+     * and legacy variants
+     */
+    public static final int METHOD_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS = 300;
 
-    public HardeningEnforcer(Context ctxt, boolean isAutomotive) {
+    public HardeningEnforcer(Context ctxt, boolean isAutomotive, AppOpsManager appOps,
+            PackageManager pm) {
         mContext = ctxt;
         mIsAutomotive = isAutomotive;
+        mAppOps = appOps;
+        mActivityManager = ctxt.getSystemService(ActivityManager.class);
+        mPackageManager = pm;
+    }
+
+    protected void dump(PrintWriter pw) {
+        // log
+        mEventLogger.dump(pw);
     }
 
     /**
@@ -84,7 +115,7 @@
             }
             // TODO metrics?
             // TODO log for audio dumpsys?
-            Log.e(TAG, "Preventing volume method " + volumeMethod + " for "
+            Slog.e(TAG, "Preventing volume method " + volumeMethod + " for "
                     + getPackNameForUid(Binder.getCallingUid()));
             return true;
         }
@@ -92,10 +123,40 @@
         return false;
     }
 
+    /**
+     * Checks whether the call in the current thread should be allowed or blocked
+     * @param focusMethod name of the method to check, for logging purposes
+     * @param clientId id of the requester
+     * @param durationHint focus type being requested
+     * @return false if the method call is allowed, true if it should be a no-op
+     */
+    protected boolean blockFocusMethod(int callingUid, int focusMethod, @NonNull String clientId,
+            int durationHint, @NonNull String packageName) {
+        if (packageName.isEmpty()) {
+            packageName = getPackNameForUid(callingUid);
+        }
+
+        if (checkAppOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, callingUid, packageName)) {
+            if (DEBUG) {
+                Slog.i(TAG, "blockFocusMethod pack:" + packageName + " NOT blocking");
+            }
+            return false;
+        }
+
+        String errorMssg = "Focus request DENIED for uid:" + callingUid
+                + " clientId:" + clientId + " req:" + durationHint
+                + " procState:" + mActivityManager.getUidProcessState(callingUid);
+
+        // TODO metrics
+        mEventLogger.enqueueAndSlog(errorMssg, EventLogger.Event.ALOGI, TAG);
+
+        return true;
+    }
+
     private String getPackNameForUid(int uid) {
         final long token = Binder.clearCallingIdentity();
         try {
-            final String[] names = mContext.getPackageManager().getPackagesForUid(uid);
+            final String[] names = mPackageManager.getPackagesForUid(uid);
             if (names == null
                     || names.length == 0
                     || TextUtils.isEmpty(names[0])) {
@@ -106,4 +167,18 @@
             Binder.restoreCallingIdentity(token);
         }
     }
+
+    /**
+     * Checks the given op without throwing
+     * @param op the appOp code
+     * @param uid the calling uid
+     * @param packageName the package name of the caller
+     * @return return false if the operation is not allowed
+     */
+    private boolean checkAppOp(int op, int uid, @NonNull String packageName) {
+        if (mAppOps.checkOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 1376bde..35d38e2 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -1090,11 +1090,14 @@
      *                  accessibility.
      * @param testUid ignored if flags doesn't contain AudioManager.AUDIOFOCUS_FLAG_TEST
      *                otherwise the UID being injected for testing
+     * @param permissionOverridesCheck true if permission checks guaranteed that the call should
+     *                                 go through, false otherwise (e.g. non-privileged caller)
      * @return
      */
     protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
             IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
-            String attributionTag, int flags, int sdk, boolean forceDuck, int testUid) {
+            String attributionTag, int flags, int sdk, boolean forceDuck, int testUid,
+            boolean permissionOverridesCheck) {
         new MediaMetrics.Item(mMetricsId)
                 .setUid(Binder.getCallingUid())
                 .set(MediaMetrics.Property.CALLING_PACKAGE, callingPackageName)
@@ -1126,10 +1129,9 @@
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
 
-        if ((flags != AudioManager.AUDIOFOCUS_FLAG_TEST)
-                // note we're using the real uid for appOp evaluation
-                && (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
-                        callingPackageName, attributionTag, null) != AppOpsManager.MODE_ALLOWED)) {
+        final int res = mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
+                callingPackageName, attributionTag, null);
+        if (!permissionOverridesCheck && res != AppOpsManager.MODE_ALLOWED) {
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 4bb8e19..bc169ca 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2901,16 +2901,12 @@
     @GuardedBy("ImfLock.class")
     void clearClientSessionsLocked() {
         if (getCurMethodLocked() != null) {
-            // TODO(b/322816970): Replace this with lambda.
-            mClientController.forAllClients(new Consumer<ClientState>() {
-
-                @GuardedBy("ImfLock.class")
-                @Override
-                public void accept(ClientState c) {
-                    clearClientSessionLocked(c);
-                    clearClientSessionForAccessibilityLocked(c);
-                }
-            });
+            // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
+            @SuppressWarnings("GuardedBy") Consumer<ClientState> clearClientSession = c -> {
+                clearClientSessionLocked(c);
+                clearClientSessionForAccessibilityLocked(c);
+            };
+            mClientController.forAllClients(clearClientSession);
 
             finishSessionLocked(mEnabledSession);
             for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
@@ -4653,15 +4649,7 @@
         super.startImeTrace_enforcePermission();
         ImeTracing.getInstance().startTrace(null /* printwriter */);
         synchronized (ImfLock.class) {
-            // TODO(b/322816970): Replace this with lambda.
-            mClientController.forAllClients(new Consumer<ClientState>() {
-
-                @GuardedBy("ImfLock.class")
-                @Override
-                public void accept(ClientState c) {
-                    c.mClient.setImeTraceEnabled(true /* enabled */);
-                }
-            });
+            mClientController.forAllClients(c -> c.mClient.setImeTraceEnabled(true /* enabled */));
         }
     }
 
@@ -4673,15 +4661,7 @@
 
         ImeTracing.getInstance().stopTrace(null /* printwriter */);
         synchronized (ImfLock.class) {
-            // TODO(b/322816970): Replace this with lambda.
-            mClientController.forAllClients(new Consumer<ClientState>() {
-
-                @GuardedBy("ImfLock.class")
-                @Override
-                public void accept(ClientState c) {
-                    c.mClient.setImeTraceEnabled(false /* enabled */);
-                }
-            });
+            mClientController.forAllClients(c -> c.mClient.setImeTraceEnabled(false /* enabled */));
         }
     }
 
@@ -5916,15 +5896,12 @@
                 // We only have sessions when we bound to an input method. Remove this session
                 // from all clients.
                 if (getCurMethodLocked() != null) {
-                    // TODO(b/322816970): Replace this with lambda.
-                    mClientController.forAllClients(new Consumer<ClientState>() {
+                    // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
+                    @SuppressWarnings("GuardedBy") Consumer<ClientState> clearClientSession =
+                            c -> clearClientSessionForAccessibilityLocked(c,
+                                    accessibilityConnectionId);
+                    mClientController.forAllClients(clearClientSession);
 
-                        @GuardedBy("ImfLock.class")
-                        @Override
-                        public void accept(ClientState c) {
-                            clearClientSessionForAccessibilityLocked(c, accessibilityConnectionId);
-                        }
-                    });
                     AccessibilitySessionState session = mEnabledAccessibilitySessions.get(
                             accessibilityConnectionId);
                     if (session != null) {
@@ -6126,24 +6103,21 @@
             }
             // Dump ClientController#mClients
             p.println("  ClientStates:");
-            // TODO(b/322816970): Replace this with lambda.
-            mClientController.forAllClients(new Consumer<ClientState>() {
+            // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
+            @SuppressWarnings("GuardedBy") Consumer<ClientState> clientControllerDump = c -> {
+                p.println("  " + c + ":");
+                p.println("    client=" + c.mClient);
+                p.println("    fallbackInputConnection="
+                        + c.mFallbackInputConnection);
+                p.println("    sessionRequested="
+                        + c.mSessionRequested);
+                p.println(
+                        "    sessionRequestedForAccessibility="
+                                + c.mSessionRequestedForAccessibility);
+                p.println("    curSession=" + c.mCurSession);
+            };
+            mClientController.forAllClients(clientControllerDump);
 
-                @GuardedBy("ImfLock.class")
-                @Override
-                public void accept(ClientState c) {
-                    p.println("  " + c + ":");
-                    p.println("    client=" + c.mClient);
-                    p.println("    fallbackInputConnection="
-                            + c.mFallbackInputConnection);
-                    p.println("    sessionRequested="
-                            + c.mSessionRequested);
-                    p.println(
-                            "    sessionRequestedForAccessibility="
-                                    + c.mSessionRequestedForAccessibility);
-                    p.println("    curSession=" + c.mCurSession);
-                }
-            });
             p.println("  mCurMethodId=" + getSelectedMethodIdLocked());
             client = mCurClient;
             p.println("  mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
deleted file mode 100644
index ac42646..0000000
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.location.GeocoderParams;
-import android.location.IGeocodeListener;
-import android.location.IGeocodeProvider;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import com.android.server.servicewatcher.CurrentUserServiceSupplier;
-import com.android.server.servicewatcher.ServiceWatcher;
-
-import java.util.Collections;
-
-/**
- * Proxy for IGeocodeProvider implementations.
- *
- * @hide
- */
-public class GeocoderProxy {
-
-    private static final String SERVICE_ACTION = "com.android.location.service.GeocodeProvider";
-
-    /**
-     * Creates and registers this proxy. If no suitable service is available for the proxy, returns
-     * null.
-     */
-    @Nullable
-    public static GeocoderProxy createAndRegister(Context context) {
-        GeocoderProxy proxy = new GeocoderProxy(context);
-        if (proxy.register()) {
-            return proxy;
-        } else {
-            return null;
-        }
-    }
-
-    private final ServiceWatcher mServiceWatcher;
-
-    private GeocoderProxy(Context context) {
-        mServiceWatcher = ServiceWatcher.create(context, "GeocoderProxy",
-                CurrentUserServiceSupplier.createFromConfig(context, SERVICE_ACTION,
-                        com.android.internal.R.bool.config_enableGeocoderOverlay,
-                        com.android.internal.R.string.config_geocoderProviderPackageName),
-                null);
-    }
-
-    private boolean register() {
-        boolean resolves = mServiceWatcher.checkServiceResolves();
-        if (resolves) {
-            mServiceWatcher.register();
-        }
-        return resolves;
-    }
-
-    /**
-     * Geocodes stuff.
-     */
-    public void getFromLocation(double latitude, double longitude, int maxResults,
-            GeocoderParams params, IGeocodeListener listener) {
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderOperation() {
-            @Override
-            public void run(IBinder binder) throws RemoteException {
-                IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
-                provider.getFromLocation(latitude, longitude, maxResults, params, listener);
-            }
-
-            @Override
-            public void onError(Throwable t) {
-                try {
-                    listener.onResults(t.toString(), Collections.emptyList());
-                } catch (RemoteException e) {
-                    // ignore
-                }
-            }
-        });
-    }
-
-    /**
-     * Geocodes stuff.
-     */
-    public void getFromLocationName(String locationName,
-            double lowerLeftLatitude, double lowerLeftLongitude,
-            double upperRightLatitude, double upperRightLongitude, int maxResults,
-            GeocoderParams params, IGeocodeListener listener) {
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderOperation() {
-            @Override
-            public void run(IBinder binder) throws RemoteException {
-                IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
-                provider.getFromLocationName(locationName, lowerLeftLatitude,
-                        lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
-                        maxResults, params, listener);
-            }
-
-            @Override
-            public void onError(Throwable t) {
-                try {
-                    listener.onResults(t.toString(), Collections.emptyList());
-                } catch (RemoteException e) {
-                    // ignore
-                }
-            }
-        });
-    }
-}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 323cdc5..c5f3855 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -52,13 +52,11 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.location.Criteria;
-import android.location.GeocoderParams;
 import android.location.Geofence;
 import android.location.GnssAntennaInfo;
 import android.location.GnssCapabilities;
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementRequest;
-import android.location.IGeocodeListener;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssNavigationMessageListener;
@@ -75,8 +73,11 @@
 import android.location.LocationProvider;
 import android.location.LocationRequest;
 import android.location.LocationTime;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.IGeocodeCallback;
 import android.location.provider.IProviderRequestListener;
 import android.location.provider.ProviderProperties;
+import android.location.provider.ReverseGeocodeRequest;
 import android.location.util.identity.CallerIdentity;
 import android.os.Binder;
 import android.os.Build;
@@ -141,6 +142,7 @@
 import com.android.server.location.provider.PassiveLocationProvider;
 import com.android.server.location.provider.PassiveLocationProviderManager;
 import com.android.server.location.provider.StationaryThrottlingLocationProvider;
+import com.android.server.location.provider.proxy.ProxyGeocodeProvider;
 import com.android.server.location.provider.proxy.ProxyLocationProvider;
 import com.android.server.location.settings.LocationSettings;
 import com.android.server.location.settings.LocationUserSettings;
@@ -253,7 +255,7 @@
 
     private final GeofenceManager mGeofenceManager;
     private volatile @Nullable GnssManagerService mGnssManagerService = null;
-    private GeocoderProxy mGeocodeProvider;
+    private ProxyGeocodeProvider mGeocodeProvider;
 
     private final Object mDeprecatedGnssBatchingLock = new Object();
     @GuardedBy("mDeprecatedGnssBatchingLock")
@@ -493,7 +495,7 @@
         }
 
         // bind to geocoder provider
-        mGeocodeProvider = GeocoderProxy.createAndRegister(mContext);
+        mGeocodeProvider = ProxyGeocodeProvider.createAndRegister(mContext);
         if (mGeocodeProvider == null) {
             Log.e(TAG, "no geocoder provider found");
         }
@@ -1363,23 +1365,22 @@
     }
 
     @Override
-    public boolean geocoderIsPresent() {
+    public boolean isGeocodeAvailable() {
         return mGeocodeProvider != null;
     }
 
     @Override
-    public void getFromLocation(double latitude, double longitude, int maxResults,
-            GeocoderParams params, IGeocodeListener listener) {
-        // validate identity
-        CallerIdentity identity = CallerIdentity.fromBinder(mContext, params.getClientPackage(),
-                params.getClientAttributionTag());
-        Preconditions.checkArgument(identity.getUid() == params.getClientUid());
+    public void reverseGeocode(ReverseGeocodeRequest request, IGeocodeCallback callback) {
+        CallerIdentity identity =
+                CallerIdentity.fromBinder(
+                        mContext, request.getCallingPackage(), request.getCallingAttributionTag());
+        Preconditions.checkArgument(identity.getUid() == request.getCallingUid());
 
         if (mGeocodeProvider != null) {
-            mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, params, listener);
+            mGeocodeProvider.reverseGeocode(request, callback);
         } else {
             try {
-                listener.onResults(null, Collections.emptyList());
+                callback.onError(null);
             } catch (RemoteException e) {
                 // ignore
             }
@@ -1387,22 +1388,17 @@
     }
 
     @Override
-    public void getFromLocationName(String locationName,
-            double lowerLeftLatitude, double lowerLeftLongitude,
-            double upperRightLatitude, double upperRightLongitude, int maxResults,
-            GeocoderParams params, IGeocodeListener listener) {
-        // validate identity
-        CallerIdentity identity = CallerIdentity.fromBinder(mContext, params.getClientPackage(),
-                params.getClientAttributionTag());
-        Preconditions.checkArgument(identity.getUid() == params.getClientUid());
+    public void forwardGeocode(ForwardGeocodeRequest request, IGeocodeCallback callback) {
+        CallerIdentity identity =
+                CallerIdentity.fromBinder(
+                        mContext, request.getCallingPackage(), request.getCallingAttributionTag());
+        Preconditions.checkArgument(identity.getUid() == request.getCallingUid());
 
         if (mGeocodeProvider != null) {
-            mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
-                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
-                    maxResults, params, listener);
+            mGeocodeProvider.forwardGeocode(request, callback);
         } else {
             try {
-                listener.onResults(null, Collections.emptyList());
+                callback.onError(null);
             } catch (RemoteException e) {
                 // ignore
             }
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyGeocodeProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyGeocodeProvider.java
new file mode 100644
index 0000000..ac945f1
--- /dev/null
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyGeocodeProvider.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.provider.proxy;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.GeocodeProviderBase;
+import android.location.provider.IGeocodeCallback;
+import android.location.provider.IGeocodeProvider;
+import android.location.provider.ReverseGeocodeRequest;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.server.servicewatcher.CurrentUserServiceSupplier;
+import com.android.server.servicewatcher.ServiceWatcher;
+
+/** Proxy for IGeocodeProvider implementations. */
+public class ProxyGeocodeProvider {
+
+    /**
+     * Creates and registers this proxy. If no suitable service is available for the proxy, returns
+     * null.
+     */
+    @Nullable
+    public static ProxyGeocodeProvider createAndRegister(Context context) {
+        ProxyGeocodeProvider proxy = new ProxyGeocodeProvider(context);
+        if (proxy.register()) {
+            return proxy;
+        } else {
+            return null;
+        }
+    }
+
+    private final ServiceWatcher mServiceWatcher;
+
+    private ProxyGeocodeProvider(Context context) {
+        mServiceWatcher =
+                ServiceWatcher.create(
+                        context,
+                        "GeocoderProxy",
+                        CurrentUserServiceSupplier.createFromConfig(
+                                context,
+                                GeocodeProviderBase.ACTION_GEOCODE_PROVIDER,
+                                com.android.internal.R.bool.config_enableGeocoderOverlay,
+                                com.android.internal.R.string.config_geocoderProviderPackageName),
+                        null);
+    }
+
+    private boolean register() {
+        boolean resolves = mServiceWatcher.checkServiceResolves();
+        if (resolves) {
+            mServiceWatcher.register();
+        }
+        return resolves;
+    }
+
+    /** Reverse geocodes. */
+    public void reverseGeocode(ReverseGeocodeRequest request, IGeocodeCallback callback) {
+        mServiceWatcher.runOnBinder(
+                new ServiceWatcher.BinderOperation() {
+                    @Override
+                    public void run(IBinder binder) throws RemoteException {
+                        IGeocodeProvider.Stub.asInterface(binder).reverseGeocode(request, callback);
+                    }
+
+                    @Override
+                    public void onError(Throwable t) {
+                        try {
+                            callback.onError(t.toString());
+                        } catch (RemoteException e) {
+                            // ignore
+                        }
+                    }
+                });
+    }
+
+    /** Forward geocodes. */
+    public void forwardGeocode(ForwardGeocodeRequest request, IGeocodeCallback callback) {
+        mServiceWatcher.runOnBinder(
+                new ServiceWatcher.BinderOperation() {
+                    @Override
+                    public void run(IBinder binder) throws RemoteException {
+                        IGeocodeProvider.Stub.asInterface(binder).forwardGeocode(request, callback);
+                    }
+
+                    @Override
+                    public void onError(Throwable t) {
+                        try {
+                            callback.onError(t.toString());
+                        } catch (RemoteException e) {
+                            // ignore
+                        }
+                    }
+                });
+    }
+}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 1546895..bbb19e3 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -550,8 +550,8 @@
                     break;
                 case RECORD_CONTENT_TASK:
                     IBinder taskWindowContainerToken =
-                            mProjectionGrant.getLaunchCookieInternal() == null ? null
-                                    : mProjectionGrant.getLaunchCookieInternal().binder;
+                            mProjectionGrant.getLaunchCookie() == null ? null
+                                    : mProjectionGrant.getLaunchCookie().binder;
                     setReviewedConsentSessionLocked(
                             ContentRecordingSession.createTaskSession(taskWindowContainerToken));
                     break;
@@ -603,17 +603,6 @@
         return projection;
     }
 
-    /**
-     * Test API mirroring the types in the aidl interface for access outside the projection
-     * package.
-     */
-    @VisibleForTesting
-    public IMediaProjection createProjectionInternal(int processUid, String packageName, int type,
-            boolean isPermanentGrant) {
-        return createProjectionInternal(processUid, packageName, type, isPermanentGrant,
-                Binder.getCallingUserHandle());
-    }
-
     // TODO(b/261563516): Remove internal method and test aidl directly, here and elsewhere.
     @VisibleForTesting
     MediaProjection getProjectionInternal(int uid, String packageName) {
@@ -1203,10 +1192,6 @@
         @Override // Binder call
         public void setLaunchCookie(LaunchCookie launchCookie) {
             setLaunchCookie_enforcePermission();
-            setLaunchCookieInternal(launchCookie);
-        }
-
-        @VisibleForTesting void setLaunchCookieInternal(LaunchCookie launchCookie) {
             mLaunchCookie = launchCookie;
         }
 
@@ -1214,10 +1199,6 @@
         @Override // Binder call
         public LaunchCookie getLaunchCookie() {
             getLaunchCookie_enforcePermission();
-            return getLaunchCookieInternal();
-        }
-
-        @VisibleForTesting LaunchCookie getLaunchCookieInternal() {
             return mLaunchCookie;
         }
 
@@ -1225,11 +1206,6 @@
         @Override
         public boolean isValid() {
             isValid_enforcePermission();
-            return isValidInternal();
-        }
-
-        @VisibleForTesting
-        boolean isValidInternal() {
             synchronized (mLock) {
                 final long curMs = mClock.uptimeMillis();
                 final boolean hasTimedOut = curMs - mCreateTimeMs > mTimeoutMs;
@@ -1260,11 +1236,6 @@
         @Override
         public void notifyVirtualDisplayCreated(int displayId) {
             notifyVirtualDisplayCreated_enforcePermission();
-            notifyVirtualDisplayCreatedInternal(displayId);
-        }
-
-        @VisibleForTesting
-        void notifyVirtualDisplayCreatedInternal(int displayId) {
             synchronized (mLock) {
                 mVirtualDisplayId = displayId;
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f9ffb1c..b5c51af 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -26,6 +26,8 @@
 import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
 import static android.Manifest.permission.READ_PHONE_STATE;
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
 import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
 import static android.app.ActivityManager.isProcStateConsideredInteraction;
 import static android.app.ActivityManager.printCapabilitiesSummary;
@@ -85,8 +87,10 @@
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_TOP;
+import static android.net.NetworkPolicyManager.BACKGROUND_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
+import static android.net.NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -97,6 +101,7 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE;
 import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
+import static android.net.NetworkPolicyManager.TOP_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.allowedReasonsToString;
 import static android.net.NetworkPolicyManager.blockedReasonsToString;
 import static android.net.NetworkPolicyManager.isProcStateAllowedNetworkWhileBackground;
@@ -469,7 +474,8 @@
      */
     private static final int MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS = 24;
 
-    private static final int UID_MSG_STATE_CHANGED = 100;
+    @VisibleForTesting
+    static final int UID_MSG_STATE_CHANGED = 100;
     private static final int UID_MSG_GONE = 101;
 
     private static final String PROP_SUB_PLAN_OWNER = "persist.sys.sub_plan_owner";
@@ -1075,8 +1081,6 @@
 
                 final int cutpoint = mBackgroundNetworkRestricted ? PROCESS_STATE_UNKNOWN
                         : NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE;
-                // TODO (b/319728914): Filter out the unnecessary changes when using no cutpoint.
-
                 mActivityManagerInternal.registerNetworkPolicyUidObserver(mUidObserver, changes,
                         cutpoint, "android");
                 mNetworkManager.registerObserver(mAlertObserver);
@@ -1185,6 +1189,51 @@
     }
 
     final private IUidObserver mUidObserver = new UidObserver() {
+
+        /**
+         * Returns whether the uid state change information is relevant for the service. If the
+         * state information does not lead to any change in the network rules, it can safely be
+         * ignored.
+         */
+        @GuardedBy("mUidStateCallbackInfos")
+        private boolean isUidStateChangeRelevant(UidStateCallbackInfo previousInfo,
+                int newProcState, long newProcStateSeq, int newCapability) {
+            if (previousInfo.procStateSeq == -1) {
+                // No previous record. Always process the first state change callback.
+                return true;
+            }
+            if (newProcStateSeq <= previousInfo.procStateSeq) {
+                // Stale callback. Ignore.
+                return false;
+            }
+            final int previousProcState = previousInfo.procState;
+            if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE)
+                    != (newProcState >= BACKGROUND_THRESHOLD_STATE)) {
+                // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the
+                // BACKGROUND chain may change.
+                return true;
+            }
+            if ((previousProcState <= TOP_THRESHOLD_STATE)
+                    != (newProcState <= TOP_THRESHOLD_STATE)) {
+                // Proc-state change crossed TOP_THRESHOLD_STATE: Network rules for the
+                // LOW_POWER_STANDBY chain may change.
+                return true;
+            }
+            if ((previousProcState <= FOREGROUND_THRESHOLD_STATE)
+                    != (newProcState <= FOREGROUND_THRESHOLD_STATE)) {
+                // Proc-state change crossed FOREGROUND_THRESHOLD_STATE: Network rules for many
+                // different chains may change.
+                return true;
+            }
+            final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
+                    | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+            if ((previousInfo.capability & networkCapabilities)
+                    != (newCapability & networkCapabilities)) {
+                return true;
+            }
+            return false;
+        }
+
         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
                 @ProcessCapability int capability) {
             synchronized (mUidStateCallbackInfos) {
@@ -1193,13 +1242,13 @@
                     callbackInfo = new UidStateCallbackInfo();
                     mUidStateCallbackInfos.put(uid, callbackInfo);
                 }
-                if (callbackInfo.procStateSeq == -1 || procStateSeq > callbackInfo.procStateSeq) {
+                if (isUidStateChangeRelevant(callbackInfo, procState, procStateSeq, capability)) {
                     callbackInfo.update(uid, procState, procStateSeq, capability);
-                }
-                if (!callbackInfo.isPending) {
-                    mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
-                            .sendToTarget();
-                    callbackInfo.isPending = true;
+                    if (!callbackInfo.isPending) {
+                        mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
+                                .sendToTarget();
+                        callbackInfo.isPending = true;
+                    }
                 }
             }
         }
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/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 85d2df3..bbce26c 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -27,11 +27,14 @@
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
 import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.Flags;
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -50,9 +53,15 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Set;
 
 final class PackageAbiHelperImpl implements PackageAbiHelper {
 
+    @Nullable
+    private static String[] sNativelySupported32BitAbis = null;
+    @Nullable
+    private static String[] sNativelySupported64BitAbis = null;
+
     private static String calculateBundledApkRoot(final String codePathString) {
         final File codePath = new File(codePathString);
         final File codeRoot;
@@ -122,13 +131,20 @@
         }
     }
 
-    private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
-            PackageManagerException {
+    private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet,
+            boolean forceMatch) throws PackageManagerException {
         if (copyRet < 0) {
             if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
                     && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
                 throw new PackageManagerException(copyRet, message);
             }
+
+            if (forceMatch && copyRet == PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+                throw new PackageManagerException(
+                        PackageManager.INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS,
+                        "The multiArch app's native libs don't support all the natively"
+                                + " supported ABIs of the device.");
+            }
         }
     }
 
@@ -296,7 +312,40 @@
         return new Abis(primaryCpuAbi, secondaryCpuAbi);
     }
 
+    @NonNull
+    private static String[] getNativelySupportedAbis(@NonNull String[] supportedAbis) {
+        Set<String> nativelySupportedAbis = new ArraySet<>();
+        for (int i = 0; i < supportedAbis.length; i++) {
+            final String currentAbi = supportedAbis[i];
+            // In presence of a native bridge this means the Abi is emulated.
+            final String currentIsa = VMRuntime.getInstructionSet(currentAbi);
+            if (TextUtils.isEmpty(SystemProperties.get("ro.dalvik.vm.isa." + currentIsa))) {
+                nativelySupportedAbis.add(currentAbi);
+            }
+        }
+        return nativelySupportedAbis.toArray(new String[0]);
+    }
+
+    private static String[] getNativelySupported32BitAbis() {
+        if (sNativelySupported32BitAbis != null) {
+            return sNativelySupported32BitAbis;
+        }
+
+        sNativelySupported32BitAbis = getNativelySupportedAbis(Build.SUPPORTED_32_BIT_ABIS);
+        return sNativelySupported32BitAbis;
+    }
+
+    private static String[] getNativelySupported64BitAbis() {
+        if (sNativelySupported64BitAbis != null) {
+            return sNativelySupported64BitAbis;
+        }
+
+        sNativelySupported64BitAbis = getNativelySupportedAbis(Build.SUPPORTED_64_BIT_ABIS);
+        return sNativelySupported64BitAbis;
+    }
+
     @Override
+    @SuppressWarnings("AndroidFrameworkCompatChange") // the check is before the apk is installed
     public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isSystemApp,
             boolean isUpdatedSystemApp, String cpuAbiOverride, File appLib32InstallDir)
             throws PackageManagerException {
@@ -334,18 +383,33 @@
             primaryCpuAbi = null;
             secondaryCpuAbi = null;
             if (pkg.isMultiArch()) {
+                // Force the match for these cases
+                // 1. pkg.getTargetSdkVersion >= Build.VERSION_CODES.VANILLA_ICE_CREAM
+                // 2. cpuAbiOverride is null. If it is non-null, it is set via shell for testing
+                final boolean forceMatch = Flags.forceMultiArchNativeLibsMatch()
+                        && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.VANILLA_ICE_CREAM
+                        && cpuAbiOverride == null;
+
+                String[] supported32BitAbis = forceMatch ? getNativelySupported32BitAbis()
+                        : Build.SUPPORTED_32_BIT_ABIS;
+                String[] supported64BitAbis = forceMatch ? getNativelySupported64BitAbis()
+                        : Build.SUPPORTED_64_BIT_ABIS;
+
+                final boolean systemSupports32BitAbi = supported32BitAbis.length > 0;
+                final boolean systemSupports64BitAbi = supported64BitAbis.length > 0;
+
                 int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
                 int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
-                if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+                if (systemSupports32BitAbi) {
                     if (extractLibs) {
                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
                         abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+                                nativeLibraryRoot, supported32BitAbis,
                                 useIsaSpecificSubdirs, onIncremental);
                     } else {
                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
                         abi32 = NativeLibraryHelper.findSupportedAbi(
-                                handle, Build.SUPPORTED_32_BIT_ABIS);
+                                handle, supported32BitAbis);
                     }
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
@@ -357,24 +421,26 @@
                 }
 
                 maybeThrowExceptionForMultiArchCopy(
-                        "Error unpackaging 32 bit native libs for multiarch app.", abi32);
+                        "Error unpackaging 32 bit native libs for multiarch app.", abi32,
+                        forceMatch && systemSupports32BitAbi);
 
-                if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+                if (systemSupports64BitAbi) {
                     if (extractLibs) {
                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
                         abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+                                nativeLibraryRoot, supported64BitAbis,
                                 useIsaSpecificSubdirs, onIncremental);
                     } else {
                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
                         abi64 = NativeLibraryHelper.findSupportedAbi(
-                                handle, Build.SUPPORTED_64_BIT_ABIS);
+                                handle, supported64BitAbis);
                     }
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
 
                 maybeThrowExceptionForMultiArchCopy(
-                        "Error unpackaging 64 bit native libs for multiarch app.", abi64);
+                        "Error unpackaging 64 bit native libs for multiarch app.", abi64,
+                        forceMatch && systemSupports64BitAbi);
 
                 if (abi64 >= 0) {
                     // Shared library native libs should be in the APK zip aligned
@@ -382,11 +448,11 @@
                         throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                                 "Shared library native lib extraction not supported");
                     }
-                    primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+                    primaryCpuAbi = supported64BitAbis[abi64];
                 }
 
                 if (abi32 >= 0) {
-                    final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+                    final String abi = supported32BitAbis[abi32];
                     if (abi64 >= 0) {
                         if (pkg.is32BitAbiPreferred()) {
                             secondaryCpuAbi = primaryCpuAbi;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index f44fcf0..21e2bf2 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -42,6 +42,7 @@
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.AttributionFlags;
 import android.app.IActivityManager;
+import android.companion.virtual.VirtualDeviceManager;
 import android.content.AttributionSource;
 import android.content.AttributionSourceState;
 import android.content.Context;
@@ -78,6 +79,7 @@
 import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.LocalServices;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.HotwordDetectionServiceProvider;
 import com.android.server.pm.pkg.AndroidPackage;
@@ -135,6 +137,9 @@
     @Nullable
     private HotwordDetectionServiceProvider mHotwordDetectionServiceProvider;
 
+    @Nullable
+    private VirtualDeviceManagerInternal mVirtualDeviceManagerInternal;
+
     PermissionManagerService(@NonNull Context context,
             @NonNull ArrayMap<String, FeatureInfo> availableFeatures) {
         // The package info cache is the cache for package and permission information.
@@ -146,6 +151,8 @@
         mContext = context;
         mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
+        mVirtualDeviceManagerInternal =
+                LocalServices.getService(VirtualDeviceManagerInternal.class);
 
         mAttributionSourceRegistry = new AttributionSourceRegistry(context);
 
@@ -246,16 +253,30 @@
             return PackageManager.PERMISSION_DENIED;
         }
 
+        String persistentDeviceId = getPersistentDeviceId(deviceId);
+
         final CheckPermissionDelegate checkPermissionDelegate;
         synchronized (mLock) {
             checkPermissionDelegate = mCheckPermissionDelegate;
         }
-
-        if (checkPermissionDelegate == null)  {
-            return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName, deviceId);
+        if (checkPermissionDelegate == null) {
+            return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName,
+                    persistentDeviceId);
         }
         return checkPermissionDelegate.checkUidPermission(uid, permissionName,
-                deviceId, mPermissionManagerServiceImpl::checkUidPermission);
+                persistentDeviceId, mPermissionManagerServiceImpl::checkUidPermission);
+    }
+
+    private String getPersistentDeviceId(int deviceId) {
+        if (deviceId == Context.DEVICE_ID_DEFAULT) {
+            return VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
+        }
+
+        if (mVirtualDeviceManagerInternal == null) {
+            mVirtualDeviceManagerInternal =
+                    LocalServices.getService(VirtualDeviceManagerInternal.class);
+        }
+        return mVirtualDeviceManagerInternal.getPersistentIdForDevice(deviceId);
     }
 
     @Override
@@ -608,15 +629,17 @@
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
             int deviceId, int userId) {
+        String persistentDeviceId = getPersistentDeviceId(deviceId);
         return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
-                permissionName, deviceId, userId);
+                permissionName, persistentDeviceId, userId);
     }
 
     @Override
     public boolean isPermissionRevokedByPolicy(String packageName, String permissionName,
             int deviceId, int userId) {
+        String persistentDeviceId = getPersistentDeviceId(deviceId);
         return mPermissionManagerServiceImpl.isPermissionRevokedByPolicy(packageName,
-                permissionName, deviceId, userId);
+                permissionName, persistentDeviceId, userId);
     }
 
     @Override
@@ -914,13 +937,13 @@
          *
          * @param uid the UID to be checked
          * @param permissionName the name of the permission to be checked
-         * @param deviceId The device ID
+         * @param persistentDeviceId The persistent device ID
          * @param superImpl the original implementation that can be delegated to
          * @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
          * the permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} otherwise
          */
-        int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
-                TriFunction<Integer, String, Integer, Integer> superImpl);
+        int checkUidPermission(int uid, @NonNull String permissionName, String persistentDeviceId,
+                TriFunction<Integer, String, String, Integer> superImpl);
 
         /**
          * @return list of delegated permissions
@@ -965,17 +988,18 @@
         }
 
         @Override
-        public int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
-                @NonNull TriFunction<Integer, String, Integer, Integer> superImpl) {
+        public int checkUidPermission(int uid, @NonNull String permissionName,
+                String persistentDeviceId,
+                @NonNull TriFunction<Integer, String, String, Integer> superImpl) {
             if (uid == mDelegatedUid && isDelegatedPermission(permissionName)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    return superImpl.apply(Process.SHELL_UID, permissionName, deviceId);
+                    return superImpl.apply(Process.SHELL_UID, permissionName, persistentDeviceId);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            return superImpl.apply(uid, permissionName, deviceId);
+            return superImpl.apply(uid, permissionName, persistentDeviceId);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index c5b637d..70913c3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -682,7 +682,7 @@
     }
 
     @Override
-    public int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+    public int getPermissionFlags(String packageName, String permName, String deviceId,
             int userId) {
         final int callingUid = Binder.getCallingUid();
         return getPermissionFlagsInternal(packageName, permName, callingUid, userId);
@@ -726,8 +726,7 @@
 
     @Override
     public void updatePermissionFlags(String packageName, String permName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
-            int userId) {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, String deviceId, int userId) {
         final int callingUid = Binder.getCallingUid();
         boolean overridePolicy = false;
 
@@ -917,8 +916,7 @@
     }
 
     @Override
-    public int checkPermission(String pkgName, String permName, String persistentDeviceId,
-            int userId) {
+    public int checkPermission(String pkgName, String permName, String deviceId, int userId) {
         if (!mUserManagerInt.exists(userId)) {
             return PackageManager.PERMISSION_DENIED;
         }
@@ -985,11 +983,11 @@
     }
 
     private int checkUidPermission(int uid, String permName) {
-        return checkUidPermission(uid, permName, Context.DEVICE_ID_DEFAULT);
+        return checkUidPermission(uid, permName, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
     }
 
     @Override
-    public int checkUidPermission(int uid, String permName, int deviceId) {
+    public int checkUidPermission(int uid, String permName, String deviceId) {
         final int userId = UserHandle.getUserId(uid);
         if (!mUserManagerInt.exists(userId)) {
             return PackageManager.PERMISSION_DENIED;
@@ -1001,7 +999,7 @@
 
     @Override
     public Map<String, PermissionManager.PermissionState> getAllPermissionStates(
-            @NonNull String packageName, @NonNull String persistentDeviceId, int userId) {
+            @NonNull String packageName, @NonNull String deviceId, int userId) {
         throw new UnsupportedOperationException(
                 "This method is supported in newer implementation only");
     }
@@ -1315,8 +1313,8 @@
     }
 
     @Override
-    public void grantRuntimePermission(String packageName, String permName,
-            String persistentDeviceId, int userId) {
+    public void grantRuntimePermission(String packageName, String permName, String deviceId,
+            int userId) {
         final int callingUid = Binder.getCallingUid();
         final boolean overridePolicy =
                 checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
@@ -1489,12 +1487,13 @@
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permName,
-            String persistentDeviceId, int userId, String reason) {
+    public void revokeRuntimePermission(String packageName, String permName, String deviceId,
+            int userId, String reason) {
         final int callingUid = Binder.getCallingUid();
         final boolean overridePolicy =
                 checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY,
-                        Context.DEVICE_ID_DEFAULT) == PackageManager.PERMISSION_GRANTED;
+                        VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)
+                        == PackageManager.PERMISSION_GRANTED;
 
         revokeRuntimePermissionInternal(packageName, permName, overridePolicy, callingUid, userId,
                 reason, mDefaultPermissionCallback);
@@ -1880,7 +1879,7 @@
 
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, @UserIdInt int userId) {
+            String deviceId, @UserIdInt int userId) {
         final int callingUid = Binder.getCallingUid();
         if (UserHandle.getCallingUserId() != userId) {
             mContext.enforceCallingPermission(
@@ -1943,7 +1942,7 @@
     }
 
     @Override
-    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+    public boolean isPermissionRevokedByPolicy(String packageName, String permName, String deviceId,
             int userId) {
         if (UserHandle.getCallingUserId() != userId) {
             mContext.enforceCallingPermission(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 7c10425..47032ea 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -141,11 +141,11 @@
      *
      * @param packageName the package name for which to get the flags
      * @param permName the permission for which to get the flags
-     * @param persistentDeviceId The device for which to get the flags
+     * @param deviceId The device for which to get the flags
      * @param userId the user for which to get permission flags
      * @return the permission flags
      */
-    int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+    int getPermissionFlags(String packageName, String permName, String deviceId,
             @UserIdInt int userId);
 
     /**
@@ -156,11 +156,11 @@
      * @param permName The permission for which to update the flags
      * @param flagMask The flags which to replace
      * @param flagValues The flags with which to replace
-     * @param persistentDeviceId The device for which to update the permission flags
+     * @param deviceId The device for which to update the permission flags
      * @param userId The user for which to update the permission flags
      */
     void updatePermissionFlags(String packageName, String permName, int flagMask, int flagValues,
-            boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
+            boolean checkAdjustPolicyFlagPermission, String deviceId,
             @UserIdInt int userId);
 
     /**
@@ -295,12 +295,12 @@
      *
      * @param packageName the package to which to grant the permission
      * @param permName the permission name to grant
-     * @param persistentDeviceId the device for which to grant the permission
+     * @param deviceId the device for which to grant the permission
      * @param userId the user for which to grant the permission
      *
      * @see #revokeRuntimePermission(String, String, String, int, String)
      */
-    void grantRuntimePermission(String packageName, String permName, String persistentDeviceId,
+    void grantRuntimePermission(String packageName, String permName, String deviceId,
             @UserIdInt int userId);
 
     /**
@@ -316,13 +316,13 @@
      *
      * @param packageName the package from which to revoke the permission
      * @param permName the permission name to revoke
-     * @param persistentDeviceId the device for which to revoke the permission
+     * @param deviceId the device for which to revoke the permission
      * @param userId the user for which to revoke the permission
      * @param reason the reason for the revoke, or {@code null} for unspecified
      *
      * @see #grantRuntimePermission(String, String, String, int)
      */
-    void revokeRuntimePermission(String packageName, String permName, String persistentDeviceId,
+    void revokeRuntimePermission(String packageName, String permName, String deviceId,
             @UserIdInt int userId, String reason);
 
     /**
@@ -347,7 +347,7 @@
      * @return whether you can show permission rationale UI
      */
     boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, @UserIdInt int userId);
+            String deviceId, @UserIdInt int userId);
 
     /**
      * Checks whether a particular permission has been revoked for a package by policy. Typically,
@@ -361,8 +361,8 @@
      * @param userId the device for which you are checking the permission
      * @return whether the permission is restricted by policy
      */
-    boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
-            @UserIdInt int userId);
+    boolean isPermissionRevokedByPolicy(String packageName, String permName,
+            String deviceId, @UserIdInt int userId);
 
     /**
      * Get set of permissions that have been split into more granular or dependent permissions.
@@ -389,11 +389,11 @@
      *
      * @param pkgName package name
      * @param permName permission name
-     * @param persistentDeviceId  persistent device ID
+     * @param deviceId  persistent device ID
      * @param userId user ID
      * @return permission result {@link PackageManager.PermissionResult}
      */
-    int checkPermission(String pkgName, String permName, String persistentDeviceId,
+    int checkPermission(String pkgName, String permName, String deviceId,
             @UserIdInt int userId);
 
     /**
@@ -401,23 +401,23 @@
      *
      * @param uid UID
      * @param permName permission name
-     * @param deviceId device ID
+     * @param deviceId persistent device ID
      * @return permission result {@link PackageManager.PermissionResult}
      */
-    int checkUidPermission(int uid, String permName, int deviceId);
+    int checkUidPermission(int uid, String permName, String deviceId);
 
     /**
      * Gets the permission states for requested package, persistent device and user.
      *
      * @param packageName name of the package you are checking against
-     * @param persistentDeviceId id of the persistent device you are checking against
+     * @param deviceId id of the persistent device you are checking against
      * @param userId id of the user for which to get permission flags
      * @return mapping of all permission states keyed by their permission names
      *
      * @hide
      */
     Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
-            @NonNull String persistentDeviceId, @UserIdInt int userId);
+            @NonNull String deviceId, @UserIdInt int userId);
 
     /**
      * Get all the package names requesting app op permissions.
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
index 91a778d..c18f856 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
@@ -121,24 +121,22 @@
     }
 
     @Override
-    public int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+    public int getPermissionFlags(String packageName, String permName, String deviceId,
             int userId) {
         Log.i(LOG_TAG, "getPermissionFlags(packageName = " + packageName + ", permName = "
-                + permName + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId
-                + ")");
-        return mService.getPermissionFlags(packageName, permName, persistentDeviceId, userId);
+                + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+        return mService.getPermissionFlags(packageName, permName, deviceId, userId);
     }
 
     @Override
     public void updatePermissionFlags(String packageName, String permName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
-            int userId) {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, String deviceId, int userId) {
         Log.i(LOG_TAG, "updatePermissionFlags(packageName = " + packageName + ", permName = "
                 + permName + ", flagMask = " + flagMask + ", flagValues = " + flagValues
                 + ", checkAdjustPolicyFlagPermission = " + checkAdjustPolicyFlagPermission
-                + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId + ")");
+                + ", deviceId = " + deviceId + ", userId = " + userId + ")");
         mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
-                checkAdjustPolicyFlagPermission, persistentDeviceId, userId);
+                checkAdjustPolicyFlagPermission, deviceId, userId);
     }
 
     @Override
@@ -186,21 +184,20 @@
     }
 
     @Override
-    public void grantRuntimePermission(String packageName, String permName,
-            String persistentDeviceId, int userId) {
+    public void grantRuntimePermission(String packageName, String permName, String deviceId,
+            int userId) {
         Log.i(LOG_TAG, "grantRuntimePermission(packageName = " + packageName + ", permName = "
-                + permName + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId
-                + ")");
-        mService.grantRuntimePermission(packageName, permName, persistentDeviceId, userId);
+                + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+        mService.grantRuntimePermission(packageName, permName, deviceId, userId);
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permName,
-            String persistentDeviceId, int userId, String reason) {
+    public void revokeRuntimePermission(String packageName, String permName, String deviceId,
+            int userId, String reason) {
         Log.i(LOG_TAG, "revokeRuntimePermission(packageName = " + packageName + ", permName = "
-                + permName + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId
-                + ", reason = " + reason + ")");
-        mService.revokeRuntimePermission(packageName, permName, persistentDeviceId, userId, reason);
+                + permName + ", deviceId = " + deviceId + ", userId = " + userId + ", reason = "
+                + reason + ")");
+        mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
     }
 
     @Override
@@ -212,16 +209,16 @@
 
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, int userId) {
+            String deviceId, int userId) {
         Log.i(LOG_TAG, "shouldShowRequestPermissionRationale(packageName = " + packageName
-                + ", permName = " + permName + ", deviceId = " + deviceId
-                +  ", userId = " + userId + ")");
+                + ", permName = " + permName + ", deviceId = " + deviceId + ", userId = "
+                + userId + ")");
         return mService.shouldShowRequestPermissionRationale(packageName, permName, deviceId,
                 userId);
     }
 
     @Override
-    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+    public boolean isPermissionRevokedByPolicy(String packageName, String permName, String deviceId,
             int userId) {
         Log.i(LOG_TAG, "isPermissionRevokedByPolicy(packageName = " + packageName + ", permName = "
                 + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
@@ -235,26 +232,27 @@
     }
 
     @Override
-    public int checkPermission(String pkgName, String permName, String persistentDeviceId,
+    public int checkPermission(String pkgName, String permName, String deviceId,
             int userId) {
         Log.i(LOG_TAG, "checkPermission(pkgName = " + pkgName + ", permName = " + permName
-                + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId + ")");
-        return mService.checkPermission(pkgName, permName, persistentDeviceId, userId);
+                + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+        return mService.checkPermission(pkgName, permName, deviceId, userId);
     }
 
     @Override
-    public int checkUidPermission(int uid, String permName, int deviceId) {
-        Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = "
-                + permName + ", deviceId = " + deviceId + ")");
+    public int checkUidPermission(int uid, String permName, String deviceId) {
+        Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName
+                + ", deviceId = " + deviceId + ")");
         return mService.checkUidPermission(uid, permName, deviceId);
     }
 
     @Override
     public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
-            @NonNull String persistentDeviceId, int userId) {
-        Log.i(LOG_TAG, "getAllPermissionStates(packageName = " + packageName
-                + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId + ")");
-        return mService.getAllPermissionStates(packageName, persistentDeviceId, userId);
+            @NonNull String deviceId, int userId) {
+        Log.i(LOG_TAG,
+                "getAllPermissionStates(packageName = " + packageName + ", deviceId = " + deviceId
+                        + ", userId = " + userId + ")");
+        return mService.getAllPermissionStates(packageName, deviceId, userId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
index 0a4ff07..40139ba 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
@@ -154,12 +154,10 @@
     }
 
     @Override
-    public int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+    public int getPermissionFlags(String packageName, String permName, String deviceId,
             @UserIdInt int userId) {
-        int oldVal = mOldImplementation.getPermissionFlags(packageName, permName,
-                persistentDeviceId, userId);
-        int newVal = mNewImplementation.getPermissionFlags(packageName, permName,
-                persistentDeviceId, userId);
+        int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
+        int newVal = mNewImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
 
         if (!Objects.equals(oldVal, newVal)) {
             signalImplDifference("getPermissionFlags");
@@ -169,12 +167,12 @@
 
     @Override
     public void updatePermissionFlags(String packageName, String permName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
+            int flagValues, boolean checkAdjustPolicyFlagPermission, String deviceId,
             @UserIdInt int userId) {
         mOldImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
-                checkAdjustPolicyFlagPermission, persistentDeviceId, userId);
+                checkAdjustPolicyFlagPermission, deviceId, userId);
         mNewImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
-                checkAdjustPolicyFlagPermission, persistentDeviceId, userId);
+                checkAdjustPolicyFlagPermission, deviceId, userId);
     }
 
     @Override
@@ -239,21 +237,17 @@
     }
 
     @Override
-    public void grantRuntimePermission(String packageName, String permName,
-            String persistentDeviceId, @UserIdInt int userId) {
-        mOldImplementation.grantRuntimePermission(packageName, permName, persistentDeviceId,
-                userId);
-        mNewImplementation.grantRuntimePermission(packageName, permName, persistentDeviceId,
-                userId);
+    public void grantRuntimePermission(String packageName, String permName, String deviceId,
+            @UserIdInt int userId) {
+        mOldImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
+        mNewImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permName,
-            String persistentDeviceId, @UserIdInt int userId, String reason) {
-        mOldImplementation.revokeRuntimePermission(packageName, permName, persistentDeviceId,
-                userId, reason);
-        mNewImplementation.revokeRuntimePermission(packageName, permName, persistentDeviceId,
-                userId, reason);
+    public void revokeRuntimePermission(String packageName, String permName, String deviceId,
+            @UserIdInt int userId, String reason) {
+        mOldImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+        mNewImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
     }
 
     @Override
@@ -265,7 +259,7 @@
 
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, @UserIdInt int userId) {
+            String deviceId, @UserIdInt int userId) {
         boolean oldVal = mOldImplementation.shouldShowRequestPermissionRationale(packageName,
                 permName, deviceId,  userId);
         boolean newVal = mNewImplementation.shouldShowRequestPermissionRationale(packageName,
@@ -278,7 +272,7 @@
     }
 
     @Override
-    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+    public boolean isPermissionRevokedByPolicy(String packageName, String permName, String deviceId,
             @UserIdInt int userId) {
         boolean oldVal = mOldImplementation.isPermissionRevokedByPolicy(packageName, permName,
                 deviceId, userId);
@@ -303,12 +297,9 @@
     }
 
     @Override
-    public int checkPermission(String pkgName, String permName, String persistentDeviceId,
-            int userId) {
-        int oldVal = mOldImplementation.checkPermission(pkgName, permName, persistentDeviceId,
-                userId);
-        int newVal = mNewImplementation.checkPermission(pkgName, permName, persistentDeviceId,
-                userId);
+    public int checkPermission(String pkgName, String permName, String deviceId, int userId) {
+        int oldVal = mOldImplementation.checkPermission(pkgName, permName, deviceId, userId);
+        int newVal = mNewImplementation.checkPermission(pkgName, permName, deviceId, userId);
 
         if (!Objects.equals(oldVal, newVal)) {
             signalImplDifference("checkPermission");
@@ -317,7 +308,7 @@
     }
 
     @Override
-    public int checkUidPermission(int uid, String permName, int deviceId) {
+    public int checkUidPermission(int uid, String permName, String deviceId) {
         int oldVal = mOldImplementation.checkUidPermission(uid, permName, deviceId);
         int newVal = mNewImplementation.checkUidPermission(uid, permName, deviceId);
 
@@ -329,8 +320,8 @@
 
     @Override
     public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
-            @NonNull String persistentDeviceId, int userId) {
-        return mNewImplementation.getAllPermissionStates(packageName, persistentDeviceId, userId);
+            @NonNull String deviceId, int userId) {
+        return mNewImplementation.getAllPermissionStates(packageName, deviceId, userId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
index bc29e67..981d3d9 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
@@ -159,11 +159,11 @@
     }
 
     @Override
-    public int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+    public int getPermissionFlags(String packageName, String permName, String deviceId,
             int userId) {
         Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionFlags");
         try {
-            return mService.getPermissionFlags(packageName, permName, persistentDeviceId, userId);
+            return mService.getPermissionFlags(packageName, permName, deviceId, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
@@ -171,13 +171,12 @@
 
     @Override
     public void updatePermissionFlags(String packageName, String permName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
-            int userId) {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, String deviceId, int userId) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#updatePermissionFlags");
         try {
             mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
-                    checkAdjustPolicyFlagPermission, persistentDeviceId, userId);
+                    checkAdjustPolicyFlagPermission, deviceId, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
@@ -256,25 +255,24 @@
     }
 
     @Override
-    public void grantRuntimePermission(String packageName, String permName,
-            String persistentDeviceId, int userId) {
+    public void grantRuntimePermission(String packageName, String permName, String deviceId,
+            int userId) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#grantRuntimePermission");
         try {
-            mService.grantRuntimePermission(packageName, permName, persistentDeviceId, userId);
+            mService.grantRuntimePermission(packageName, permName, deviceId, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permName,
-            String persistentDeviceId, int userId, String reason) {
+    public void revokeRuntimePermission(String packageName, String permName, String deviceId,
+            int userId, String reason) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#revokeRuntimePermission");
         try {
-            mService.revokeRuntimePermission(packageName, permName, persistentDeviceId, userId,
-                    reason);
+            mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
@@ -293,19 +291,19 @@
 
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, int userId) {
+            String deviceId, int userId) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#shouldShowRequestPermissionRationale");
         try {
-            return mService.shouldShowRequestPermissionRationale(
-                    packageName, permName, deviceId, userId);
+            return mService.shouldShowRequestPermissionRationale(packageName, permName, deviceId,
+                    userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
     }
 
     @Override
-    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+    public boolean isPermissionRevokedByPolicy(String packageName, String permName, String deviceId,
             int userId) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#isPermissionRevokedByPolicy");
@@ -328,18 +326,17 @@
     }
 
     @Override
-    public int checkPermission(String pkgName, String permName, String persistentDeviceId,
-            int userId) {
+    public int checkPermission(String pkgName, String permName, String deviceId, int userId) {
         Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkPermission");
         try {
-            return mService.checkPermission(pkgName, permName, persistentDeviceId, userId);
+            return mService.checkPermission(pkgName, permName, deviceId, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
     }
 
     @Override
-    public int checkUidPermission(int uid, String permName, int deviceId) {
+    public int checkUidPermission(int uid, String permName, String deviceId) {
         Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkUidPermission");
         try {
             return mService.checkUidPermission(uid, permName, deviceId);
@@ -350,11 +347,11 @@
 
     @Override
     public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
-            @NonNull String persistentDeviceId, int userId) {
+            @NonNull String deviceId, int userId) {
         Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl"
                 + "#getAllPermissionStates");
         try {
-            return mService.getAllPermissionStates(packageName, persistentDeviceId, userId);
+            return mService.getAllPermissionStates(packageName, deviceId, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
diff --git a/services/core/java/com/android/server/utils/EventLogger.java b/services/core/java/com/android/server/utils/EventLogger.java
index 4772bbf..2e1049b 100644
--- a/services/core/java/com/android/server/utils/EventLogger.java
+++ b/services/core/java/com/android/server/utils/EventLogger.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.util.Log;
+import android.util.Slog;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -84,6 +85,17 @@
         enqueue(event.printLog(logType, tag));
     }
 
+    /**
+     * Add a string-based event to the system log, and print it to the log with a specific severity.
+     * @param msg the message to appear in the log
+     * @param logType the log severity (verbose/info/warning/error)
+     * @param tag the tag under which the log entry will appear
+     */
+    public synchronized void enqueueAndSlog(String msg, @Event.LogType int logType, String tag) {
+        final Event event = new StringEvent(msg);
+        enqueue(event.printSlog(logType, tag));
+    }
+
     /** Dumps events into the given {@link DumpSink}. */
     public synchronized void dump(DumpSink dumpSink) {
         dumpSink.sink(mTag, new ArrayList<>(mEvents));
@@ -138,7 +150,7 @@
         /**
          * Causes the string message for the event to appear in the logcat.
          * Here is an example of how to create a new event (a StringEvent), adding it to the logger
-         * (an instance of AudioEventLogger) while also making it show in the logcat:
+         * (an instance of EventLogger) while also making it show in the logcat:
          * <pre>
          *     myLogger.log(
          *         (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) );
@@ -167,9 +179,9 @@
 
         /**
          * Same as {@link #printLog(String)} with a log type
-         * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}
-         * @param tag
-         * @return
+         * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}, {@link #ALOGW}
+         * @param tag the tag the log entry will be printed under
+         * @return the event itself
          */
         public Event printLog(@LogType int type, String tag) {
             switch (type) {
@@ -191,6 +203,32 @@
         }
 
         /**
+         * Causes the string message for the event to appear in the system log.
+         * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}, {@link #ALOGW}
+         * @param tag the tag the log entry will be printed under
+         * @return the event itself
+         * @see #printLog(int, String)
+         */
+        public Event printSlog(@LogType int type, String tag) {
+            switch (type) {
+                case ALOGI:
+                    Slog.i(tag, eventToString());
+                    break;
+                case ALOGE:
+                    Slog.e(tag, eventToString());
+                    break;
+                case ALOGW:
+                    Slog.w(tag, eventToString());
+                    break;
+                case ALOGV:
+                default:
+                    Slog.v(tag, eventToString());
+                    break;
+            }
+            return this;
+        }
+
+        /**
          * Convert event to String.
          * This method is only called when the logger history is about to the dumped,
          * so this method is where expensive String conversions should be made, not when the Event
diff --git a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
index db27f60..01d077a 100644
--- a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
+++ b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
@@ -22,12 +22,10 @@
 
 import android.annotation.NonNull;
 import android.app.compat.CompatChanges;
-import android.content.pm.PackageManager;
 import android.provider.DeviceConfig;
 
 import com.android.internal.annotations.GuardedBy;
 
-import java.util.HashSet;
 import java.util.concurrent.Executor;
 
 /**
@@ -50,74 +48,49 @@
     private static final String KEY_ASM_RESTRICTIONS_ENABLED = KEY_ASM_PREFIX
             + "asm_restrictions_enabled";
     private static final String KEY_ASM_TOASTS_ENABLED = KEY_ASM_PREFIX + "asm_toasts_enabled";
-    private static final String KEY_ASM_EXEMPTED_PACKAGES = KEY_ASM_PREFIX
-            + "asm_exempted_packages";
+
     private static final int VALUE_DISABLE = 0;
     private static final int VALUE_ENABLE_FOR_V = 1;
     private static final int VALUE_ENABLE_FOR_ALL = 2;
 
     private static final int DEFAULT_VALUE = VALUE_DISABLE;
-    private static final String DEFAULT_EXCEPTION_LIST = "";
 
     private static int sAsmToastsEnabled;
     private static int sAsmRestrictionsEnabled;
-    private static final HashSet<String> sExcludedPackageNames = new HashSet<>();
-    private static PackageManager sPm;
 
     @GuardedBy("ActivityTaskManagerService.mGlobalLock")
-    static void initialize(@NonNull Executor executor, @NonNull PackageManager pm) {
+    static void initialize(@NonNull Executor executor) {
         updateFromDeviceConfig();
         DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, executor,
                 properties -> updateFromDeviceConfig());
-        sPm = pm;
     }
 
     @GuardedBy("ActivityTaskManagerService.mGlobalLock")
     static boolean shouldShowToast(int uid) {
-        return flagEnabledForUid(sAsmToastsEnabled, uid);
+        return sAsmToastsEnabled == VALUE_ENABLE_FOR_ALL
+                || (sAsmToastsEnabled == VALUE_ENABLE_FOR_V
+                        && CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, uid));
     }
 
     @GuardedBy("ActivityTaskManagerService.mGlobalLock")
     static boolean shouldRestrictActivitySwitch(int uid) {
-        return flagEnabledForUid(sAsmRestrictionsEnabled, uid);
-    }
-
-    private static boolean flagEnabledForUid(int flag, int uid) {
-        boolean flagEnabled = flag == VALUE_ENABLE_FOR_ALL
-                || (flag == VALUE_ENABLE_FOR_V
-                    && CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, uid));
-
-        if (flagEnabled) {
-            String[] packageNames = sPm.getPackagesForUid(uid);
-            if (packageNames == null) {
-                return true;
-            }
-            for (int i = 0; i < packageNames.length; i++) {
-                if (sExcludedPackageNames.contains(packageNames[i])) {
-                    return false;
-                }
-            }
-            return true;
+        if (android.security.Flags.asmRestrictionsEnabled()) {
+            return CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, uid)
+                    || asmRestrictionsEnabledForAll();
         }
 
         return false;
     }
 
+    @GuardedBy("ActivityTaskManagerService.mGlobalLock")
+    static boolean asmRestrictionsEnabledForAll() {
+        return sAsmRestrictionsEnabled == VALUE_ENABLE_FOR_ALL;
+    }
+
     private static void updateFromDeviceConfig() {
         sAsmToastsEnabled = DeviceConfig.getInt(NAMESPACE, KEY_ASM_TOASTS_ENABLED,
                 DEFAULT_VALUE);
         sAsmRestrictionsEnabled = DeviceConfig.getInt(NAMESPACE, KEY_ASM_RESTRICTIONS_ENABLED,
                 DEFAULT_VALUE);
-
-        String rawExceptionList = DeviceConfig.getString(NAMESPACE,
-                KEY_ASM_EXEMPTED_PACKAGES, DEFAULT_EXCEPTION_LIST);
-        sExcludedPackageNames.clear();
-        String[] packages = rawExceptionList.split(",");
-        for (String packageName : packages) {
-            String packageNameTrimmed = packageName.trim();
-            if (!packageNameTrimmed.isEmpty()) {
-                sExcludedPackageNames.add(packageNameTrimmed);
-            }
-        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0e6c06d..445295a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -881,7 +881,7 @@
             mTaskSupervisor.onSystemReady();
             mActivityClientController.onSystemReady();
             // TODO(b/258792202) Cleanup once ASM is ready to launch
-            ActivitySecurityModelFeatureFlags.initialize(mContext.getMainExecutor(), pm);
+            ActivitySecurityModelFeatureFlags.initialize(mContext.getMainExecutor());
             mGrammaticalManagerInternal = LocalServices.getService(
                     GrammaticalInflectionManagerInternal.class);
         }
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 2d6f03a..3bc5319 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -56,6 +56,7 @@
 import android.compat.annotation.EnabledAfter;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Process;
 import android.os.SystemClock;
@@ -529,6 +530,9 @@
         static final BalVerdict BLOCK = new BalVerdict(BAL_BLOCK, false, "Blocked");
         static final BalVerdict ALLOW_BY_DEFAULT =
                 new BalVerdict(BAL_ALLOW_DEFAULT, false, "Default");
+        // Careful using this - it will bypass all ASM checks.
+        static final BalVerdict ALLOW_PRIVILEGED =
+                new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, false, "PRIVILEGED");
         private final @BalCode int mCode;
         private final boolean mBackground;
         private final String mMessage;
@@ -1234,7 +1238,8 @@
         boolean shouldBlockActivityStart = ActivitySecurityModelFeatureFlags
                 .shouldRestrictActivitySwitch(callingUid);
         int[] finishCount = new int[0];
-        if (shouldBlockActivityStart) {
+        if (shouldBlockActivityStart
+                && blockCrossUidActivitySwitchFromBelowForActivity(targetTaskTop)) {
             ActivityRecord activity = targetTask.getActivity(isLaunchingOrLaunched);
             if (activity == null) {
                 // mStartActivity is not in task, so clear everything
@@ -1319,7 +1324,7 @@
 
         boolean restrictActivitySwitch = ActivitySecurityModelFeatureFlags
                 .shouldRestrictActivitySwitch(callingUid)
-                && bas.mBlockActivityStartIfFlagEnabled;
+                        && bas.mBlockActivityStartIfFlagEnabled;
 
         PackageManager pm = mService.mContext.getPackageManager();
         String callingPackage = pm.getNameForUid(callingUid);
@@ -1373,19 +1378,19 @@
             int uid, @Nullable ActivityRecord sourceRecord) {
         // If the source is visible, consider it 'top'.
         if (sourceRecord != null && sourceRecord.isVisibleRequested()) {
-            return new BlockActivityStart(false, false);
+            return BlockActivityStart.ACTIVITY_START_ALLOWED;
         }
 
         // Always allow actual top activity to clear task
         ActivityRecord topActivity = task.getTopMostActivity();
         if (topActivity != null && topActivity.isUid(uid)) {
-            return new BlockActivityStart(false, false);
+            return BlockActivityStart.ACTIVITY_START_ALLOWED;
         }
 
         // If UID is visible in target task, allow launch
         if (task.forAllActivities((Predicate<ActivityRecord>)
                 ar -> ar.isUid(uid) && ar.isVisibleRequested())) {
-            return new BlockActivityStart(false, false);
+            return BlockActivityStart.ACTIVITY_START_ALLOWED;
         }
 
         // Consider the source activity, whether or not it is finishing. Do not consider any other
@@ -1452,12 +1457,11 @@
     private BlockActivityStart blockCrossUidActivitySwitchFromBelow(ActivityRecord ar,
             int sourceUid) {
         if (ar.isUid(sourceUid)) {
-            return new BlockActivityStart(false, false);
+            return BlockActivityStart.ACTIVITY_START_ALLOWED;
         }
 
-        // If mAllowCrossUidActivitySwitchFromBelow is set, honor it.
-        if (ar.mAllowCrossUidActivitySwitchFromBelow) {
-            return new BlockActivityStart(false, false);
+        if (!blockCrossUidActivitySwitchFromBelowForActivity(ar)) {
+            return BlockActivityStart.ACTIVITY_START_ALLOWED;
         }
 
         // At this point, we would block if the feature is launched and both apps were V+
@@ -1468,8 +1472,11 @@
                 ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(ar.getUid())
                         && ActivitySecurityModelFeatureFlags
                         .shouldRestrictActivitySwitch(sourceUid);
-        return new BackgroundActivityStartController
-                .BlockActivityStart(restrictActivitySwitch, true);
+        if (restrictActivitySwitch) {
+            return BlockActivityStart.BLOCK;
+        } else {
+            return BlockActivityStart.LOG_ONLY;
+        }
     }
 
     /**
@@ -1675,14 +1682,52 @@
         }
     }
 
-    static class BlockActivityStart {
+    /**
+     * Activity level allowCrossUidActivitySwitchFromBelow defaults to false.
+     * Package level defaults to true.
+     * We block the launch if dev has explicitly set package level to false, and activity level has
+     * not opted out
+     */
+    private boolean blockCrossUidActivitySwitchFromBelowForActivity(@NonNull ActivityRecord ar) {
+        // We don't need to check package level if activity has opted out.
+        if (ar.mAllowCrossUidActivitySwitchFromBelow) {
+            return false;
+        }
+
+        if (ActivitySecurityModelFeatureFlags.asmRestrictionsEnabledForAll()) {
+            return true;
+        }
+
+        String packageName = ar.packageName;
+        if (packageName == null) {
+            return false;
+        }
+
+        PackageManager pm = mService.mContext.getPackageManager();
+        ApplicationInfo applicationInfo;
+
+        try {
+            applicationInfo = pm.getApplicationInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.wtf(TAG, "Package name: " + packageName + " not found.");
+            return false;
+        }
+
+        return !applicationInfo.allowCrossUidActivitySwitchFromBelow;
+    }
+
+    private static class BlockActivityStart {
+        private static final BlockActivityStart ACTIVITY_START_ALLOWED =
+                new BlockActivityStart(false, false);
+        private static final BlockActivityStart LOG_ONLY = new BlockActivityStart(false, true);
+        private static final BlockActivityStart BLOCK = new BlockActivityStart(true, true);
         // We should block if feature flag is enabled
         private final boolean mBlockActivityStartIfFlagEnabled;
         // Used for logging/toasts. Would we block if target sdk was V and feature was
         // enabled?
         private final boolean mWouldBlockActivityStartIgnoringFlag;
 
-        BlockActivityStart(boolean shouldBlockActivityStart,
+        private BlockActivityStart(boolean shouldBlockActivityStart,
                 boolean wouldBlockActivityStartIgnoringFlags) {
             this.mBlockActivityStartIfFlagEnabled = shouldBlockActivityStart;
             this.mWouldBlockActivityStartIgnoringFlag = wouldBlockActivityStartIgnoringFlags;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 25a5fca..e743172 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6783,14 +6783,6 @@
         return mSandboxDisplayApis;
     }
 
-    /**
-     * For testing only; inject a ContentRecorder instance.
-     */
-    @VisibleForTesting
-    void setContentRecorder(ContentRecorder contentRecorder) {
-        mContentRecorder = contentRecorder;
-    }
-
     private ContentRecorder getContentRecorder() {
         if (mContentRecorder == null) {
             mContentRecorder = new ContentRecorder(this);
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index e6ef90b..68bff43 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_EMBEDDED_WINDOWS;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -34,6 +35,9 @@
 import android.view.InputChannel;
 import android.window.InputTransferToken;
 
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.server.input.InputManagerService;
+
 /**
  * Keeps track of embedded windows.
  *
@@ -52,9 +56,13 @@
     private final Object mGlobalLock;
     private final ActivityTaskManagerService mAtmService;
 
-    EmbeddedWindowController(ActivityTaskManagerService atmService) {
+    private final InputManagerService mInputManagerService;
+
+    EmbeddedWindowController(ActivityTaskManagerService atmService,
+            InputManagerService inputManagerService) {
         mAtmService = atmService;
         mGlobalLock = atmService.getGlobalLock();
+        mInputManagerService = inputManagerService;
     }
 
     /**
@@ -135,6 +143,60 @@
         return mWindowsByWindowToken.get(windowToken);
     }
 
+    private boolean isValidTouchGestureParams(WindowState hostWindowState,
+            EmbeddedWindow embeddedWindow) {
+        if (embeddedWindow == null) {
+            ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+                    "Attempt to transfer touch gesture with non-existent embedded window");
+            return false;
+        }
+        final WindowState wsAssociatedWithEmbedded = embeddedWindow.getWindowState();
+        if (wsAssociatedWithEmbedded == null) {
+            ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+                    "Attempt to transfer touch gesture using embedded window with no associated "
+                            + "host");
+            return false;
+        }
+        if (wsAssociatedWithEmbedded.mClient.asBinder() != hostWindowState.mClient.asBinder()) {
+            ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+                    "Attempt to transfer touch gesture with host window not associated with "
+                            + "embedded window");
+            return false;
+        }
+
+        if (embeddedWindow.getInputChannelToken() == null) {
+            ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+                    "Attempt to transfer touch gesture using embedded window that has no input "
+                            + "channel");
+            return false;
+        }
+        if (hostWindowState.mInputChannelToken == null) {
+            ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+                    "Attempt to transfer touch gesture using a host window with no input channel");
+            return false;
+        }
+        return true;
+    }
+
+    boolean transferToHost(InputTransferToken embeddedWindowToken,
+            WindowState transferToHostWindowState) {
+        EmbeddedWindow ew = getByInputTransferToken(embeddedWindowToken);
+        if (!isValidTouchGestureParams(transferToHostWindowState, ew)) {
+            return false;
+        }
+        return mInputManagerService.transferTouchFocus(ew.getInputChannelToken(),
+                transferToHostWindowState.mInputChannelToken);
+    }
+
+    boolean transferToEmbedded(WindowState hostWindowState, InputTransferToken transferToToken) {
+        final EmbeddedWindowController.EmbeddedWindow ew = getByInputTransferToken(transferToToken);
+        if (!isValidTouchGestureParams(hostWindowState, ew)) {
+            return false;
+        }
+        return mInputManagerService.transferTouchFocus(hostWindowState.mInputChannelToken,
+                ew.getInputChannelToken());
+    }
+
     static class EmbeddedWindow implements InputTarget {
         final IBinder mClient;
         @Nullable final WindowState mHostWindowState;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 609ad1e..bf45804 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -612,10 +612,8 @@
     }
 
     void refreshSecureSurfaceState() {
-        forAllWindows((w) -> {
-            if (w.mHasSurface) {
-                w.setSecureLocked(w.isSecureLocked());
-            }
+        forAllWindows(w -> {
+            w.setSecureLocked(w.isSecureLocked());
         }, true /* traverseTopToBottom */);
     }
 
diff --git a/services/core/java/com/android/server/wm/SensitiveContentPackages.java b/services/core/java/com/android/server/wm/SensitiveContentPackages.java
index a7d6903b..5fe48d1 100644
--- a/services/core/java/com/android/server/wm/SensitiveContentPackages.java
+++ b/services/core/java/com/android/server/wm/SensitiveContentPackages.java
@@ -56,6 +56,17 @@
     }
 
     /**
+     * Clears apps added to collection of apps in which screen capture should be disabled.
+     *
+     * @param packageInfos set of {@link PackageInfo} whose windows should be unblocked
+     *                     from capture.
+     * @return {@code true} if packages set is modified, {@code false} otherwise.
+     */
+    public boolean removeBlockScreenCaptureForApps(@NonNull ArraySet<PackageInfo> packageInfos) {
+        return mProtectedPackages.removeAll(packageInfos);
+    }
+
+    /**
      * Clears the set of package/uid pairs that should be blocked from screen capture
      *
      * @return {@code true} if packages set is modified, {@code false} otherwise.
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 3c8c55e..975208f 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -970,40 +970,6 @@
     }
 
     @Override
-    public boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow) {
-        if (embeddedWindow == null) {
-            return false;
-        }
-
-        final long identity = Binder.clearCallingIdentity();
-        boolean didTransfer = false;
-        try {
-            didTransfer = mService.transferEmbeddedTouchFocusToHost(embeddedWindow);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-        return didTransfer;
-    }
-
-    @Override
-    public boolean transferHostTouchGestureToEmbedded(IWindow hostWindow,
-            InputTransferToken inputTransferToken) {
-        if (hostWindow == null) {
-            return false;
-        }
-
-        final long identity = Binder.clearCallingIdentity();
-        boolean didTransfer;
-        try {
-            didTransfer = mService.transferHostTouchGestureToEmbedded(this, hostWindow,
-                    inputTransferToken);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-        return didTransfer;
-    }
-
-    @Override
     public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) {
         final long identity = Binder.clearCallingIdentity();
         try {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ae4c3b9..669c61c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -1043,6 +1043,15 @@
     /**
      * Clears apps added to collection of apps in which screen capture should be disabled.
      *
+     * @param packageInfos set of {@link PackageInfo} whose windows should be unblocked
+     *                     from capture.
+     */
+    public abstract void removeBlockScreenCaptureForApps(
+            @NonNull ArraySet<PackageInfo> packageInfos);
+
+    /**
+     * Clears all apps added to collection of apps in which screen capture should be disabled.
+     *
      * <p> This clears and resets any existing set or added applications from
      * * {@link #addBlockScreenCaptureForApps(ArraySet)}
      */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 631ebcd..3d6bd4f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -101,6 +101,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_EMBEDDED_WINDOWS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
@@ -1344,7 +1345,7 @@
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
         LocalServices.addService(
                 ImeTargetVisibilityPolicy.class, new ImeTargetVisibilityPolicyImpl());
-        mEmbeddedWindowController = new EmbeddedWindowController(mAtmService);
+        mEmbeddedWindowController = new EmbeddedWindowController(mAtmService, inputManager);
 
         mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
                 mContext.getResources());
@@ -8632,6 +8633,17 @@
         }
 
         @Override
+        public void removeBlockScreenCaptureForApps(ArraySet<PackageInfo> packageInfos) {
+            synchronized (mGlobalLock) {
+                boolean modified =
+                        mSensitiveContentPackages.removeBlockScreenCaptureForApps(packageInfos);
+                if (modified) {
+                    WindowManagerService.this.refreshScreenCaptureDisabled();
+                }
+            }
+        }
+
+        @Override
         public void clearBlockedApps() {
             synchronized (mGlobalLock) {
                 boolean modified = mSensitiveContentPackages.clearBlockedApps();
@@ -9044,73 +9056,37 @@
                 null /* region */, clientToken);
     }
 
-    boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow) {
-        final IBinder windowBinder = embeddedWindow.asBinder();
-        final IBinder hostInputChannel, embeddedInputChannel;
-        synchronized (mGlobalLock) {
-            final EmbeddedWindowController.EmbeddedWindow ew =
-                mEmbeddedWindowController.getByWindowToken(windowBinder);
-            if (ew == null) {
-                Slog.w(TAG, "Attempt to transfer touch focus from non-existent embedded window");
-                return false;
-            }
-            final WindowState hostWindowState = ew.getWindowState();
-            if (hostWindowState == null) {
-                Slog.w(TAG, "Attempt to transfer touch focus from embedded window with no" +
-                    " associated host");
-                return false;
-            }
-            embeddedInputChannel = ew.getInputChannelToken();
-            if (embeddedInputChannel == null) {
-                Slog.w(TAG, "Attempt to transfer touch focus from embedded window with no input" +
-                    " channel");
-                return false;
-            }
-            hostInputChannel = hostWindowState.mInputChannelToken;
-            if (hostInputChannel == null) {
-                Slog.w(TAG, "Attempt to transfer touch focus to a host window with no" +
-                    " input channel");
-                return false;
-            }
-            return mInputManager.transferTouchFocus(embeddedInputChannel, hostInputChannel);
+    @Override
+    public boolean transferTouchGesture(InputTransferToken transferFromToken,
+            InputTransferToken transferToToken) {
+        if (transferFromToken == null || transferToToken == null) {
+            ProtoLog.e(WM_DEBUG_EMBEDDED_WINDOWS,
+                    "transferTouchGesture failed because args transferFromToken or "
+                            + "transferToToken is null");
+            return false;
         }
-    }
 
-    boolean transferHostTouchGestureToEmbedded(Session session, IWindow hostWindow,
-            InputTransferToken inputTransferToken) {
-        final IBinder hostInputChannel, embeddedInputChannel;
-        synchronized (mGlobalLock) {
-            final WindowState hostWindowState = windowForClientLocked(session, hostWindow, false);
-            if (hostWindowState == null) {
-                Slog.w(TAG, "Attempt to transfer touch gesture with invalid host window");
-                return false;
+        final long identity = Binder.clearCallingIdentity();
+        boolean didTransfer;
+        try {
+            synchronized (mGlobalLock) {
+                // If the transferToToken exists in the input to window map, it means the request
+                // is to transfer from embedded to host. Otherwise, the transferToToken
+                // represents an embedded window so transfer from host to embedded.
+                WindowState windowStateTo = mInputToWindowMap.get(transferToToken.mToken);
+                if (windowStateTo != null) {
+                    didTransfer = mEmbeddedWindowController.transferToHost(transferFromToken,
+                            windowStateTo);
+                } else {
+                    WindowState windowStateFrom = mInputToWindowMap.get(transferFromToken.mToken);
+                    didTransfer = mEmbeddedWindowController.transferToEmbedded(windowStateFrom,
+                            transferToToken);
+                }
             }
-
-            final EmbeddedWindowController.EmbeddedWindow ew =
-                    mEmbeddedWindowController.getByInputTransferToken(inputTransferToken);
-            if (ew == null || ew.mHostWindowState == null) {
-                Slog.w(TAG, "Attempt to transfer touch gesture to non-existent embedded window");
-                return false;
-            }
-            if (ew.mHostWindowState.mClient.asBinder() != hostWindow.asBinder()) {
-                Slog.w(TAG, "Attempt to transfer touch gesture to embedded window not associated"
-                        + " with host window");
-                return false;
-            }
-            embeddedInputChannel = ew.getInputChannelToken();
-            if (embeddedInputChannel == null) {
-                Slog.w(TAG, "Attempt to transfer touch focus from embedded window with no input"
-                        + " channel");
-                return false;
-            }
-            hostInputChannel = hostWindowState.mInputChannelToken;
-            if (hostInputChannel == null) {
-                Slog.w(TAG,
-                        "Attempt to transfer touch focus to a host window with no input channel");
-                return false;
-            }
-            return mInputManager.transferTouchFocus(hostInputChannel, embeddedInputChannel);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
+        return didTransfer;
     }
 
     private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e619440..58e198e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -28,10 +28,13 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUTOFILL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_BLUETOOTH;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CALLS;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION;
@@ -50,6 +53,7 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MICROPHONE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MTE;
@@ -74,6 +78,7 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_TIME;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
@@ -328,6 +333,7 @@
 import android.app.admin.DeviceStateCache;
 import android.app.admin.FactoryResetProtectionPolicy;
 import android.app.admin.FullyManagedDeviceProvisioningParams;
+import android.app.admin.IAuditLogEventsCallback;
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.IntegerPolicyValue;
 import android.app.admin.IntentFilterPolicyKey;
@@ -2060,7 +2066,7 @@
         mLockPatternUtils = injector.newLockPatternUtils();
         mLockSettingsInternal = injector.getLockSettingsInternal();
         // TODO: why does SecurityLogMonitor need to be created even when mHasFeature == false?
-        mSecurityLogMonitor = new SecurityLogMonitor(this);
+        mSecurityLogMonitor = new SecurityLogMonitor(this, mHandler);
 
         mHasFeature = mInjector.hasFeature();
         mIsWatch = mInjector.getPackageManager()
@@ -2718,8 +2724,20 @@
     }
 
     private void maybeStartSecurityLogMonitorOnActivityManagerReady() {
-        synchronized (getLockObject()) {
-            if (mInjector.securityLogIsLoggingEnabled()) {
+        if (!mInjector.securityLogIsLoggingEnabled()) {
+            return;
+        }
+
+        if (securityLogV2Enabled()) {
+            boolean auditLoggingEnabled = Boolean.TRUE.equals(
+                    mDevicePolicyEngine.getResolvedPolicy(
+                            PolicyDefinition.AUDIT_LOGGING, UserHandle.USER_ALL));
+            boolean securityLoggingEnabled = Boolean.TRUE.equals(
+                    mDevicePolicyEngine.getResolvedPolicy(
+                            PolicyDefinition.SECURITY_LOGGING, UserHandle.USER_ALL));
+            setLoggingConfiguration(securityLoggingEnabled, auditLoggingEnabled);
+        } else {
+            synchronized (getLockObject()) {
                 mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
                 mInjector.runCryptoSelfTest();
                 maybePauseDeviceWideLoggingLocked();
@@ -15780,7 +15798,22 @@
 
         @Override
         public void enforceSecurityLoggingPolicy(boolean enabled) {
-            enforceLoggingPolicy(enabled);
+            if (!securityLogV2Enabled()) {
+                return;
+            }
+            Boolean auditLoggingEnabled = mDevicePolicyEngine.getResolvedPolicy(
+                    PolicyDefinition.AUDIT_LOGGING, UserHandle.USER_ALL);
+            enforceLoggingPolicy(enabled, Boolean.TRUE.equals(auditLoggingEnabled));
+        }
+
+        @Override
+        public void enforceAuditLoggingPolicy(boolean enabled) {
+            if (!securityLogV2Enabled()) {
+                return;
+            }
+            Boolean securityLoggingEnabled = mDevicePolicyEngine.getResolvedPolicy(
+                    PolicyDefinition.SECURITY_LOGGING, UserHandle.USER_ALL);
+            enforceLoggingPolicy(Boolean.TRUE.equals(securityLoggingEnabled), enabled);
         }
 
         private List<EnforcingUser> getEnforcingUsers(Set<EnforcingAdmin> admins) {
@@ -15800,17 +15833,23 @@
         }
     }
 
-    private void enforceLoggingPolicy(boolean securityLoggingEnabled) {
-        Slogf.i(LOG_TAG, "Enforcing security logging, securityLoggingEnabled: %b",
-                securityLoggingEnabled);
-        SecurityLog.setLoggingEnabledProperty(securityLoggingEnabled);
-        if (securityLoggingEnabled) {
-            mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
+    private void enforceLoggingPolicy(
+            boolean securityLoggingEnabled, boolean auditLoggingEnabled) {
+        Slogf.i(LOG_TAG, "Enforcing logging policy, security: %b audit: %b",
+                securityLoggingEnabled, auditLoggingEnabled);
+        SecurityLog.setLoggingEnabledProperty(securityLoggingEnabled || auditLoggingEnabled);
+        setLoggingConfiguration(securityLoggingEnabled, auditLoggingEnabled);
+    }
+
+    private void setLoggingConfiguration(
+            boolean securityLoggingEnabled, boolean auditLoggingEnabled) {
+        final int loggingEnabledUser = getSecurityLoggingEnabledUser();
+        mSecurityLogMonitor.setLoggingParams(
+                loggingEnabledUser, securityLoggingEnabled, auditLoggingEnabled);
+        if (securityLoggingEnabled || auditLoggingEnabled) {
             synchronized (getLockObject()) {
                 maybePauseDeviceWideLoggingLocked();
             }
-        } else {
-            mSecurityLogMonitor.stop();
         }
     }
 
@@ -17891,6 +17930,82 @@
     }
 
     @Override
+    public void setAuditLogEnabled(String callingPackage, boolean enabled) {
+        if (!mHasFeature) {
+            return;
+        }
+        final CallerIdentity caller = getCallerIdentity(callingPackage);
+
+        if (!securityLogV2Enabled()) {
+            throw new UnsupportedOperationException("Audit log not enabled");
+        }
+
+        EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
+                null /* admin */,
+                MANAGE_DEVICE_POLICY_AUDIT_LOGGING,
+                caller.getPackageName(),
+                caller.getUserId());
+        if (enabled) {
+            mDevicePolicyEngine.setGlobalPolicy(
+                    PolicyDefinition.AUDIT_LOGGING,
+                    admin,
+                    new BooleanPolicyValue(true));
+        } else {
+            mDevicePolicyEngine.removeGlobalPolicy(
+                    PolicyDefinition.AUDIT_LOGGING,
+                    admin);
+            mSecurityLogMonitor.setAuditLogEventsCallback(caller.getUid(), null /* callback */);
+        }
+    }
+
+    @Override
+    public boolean isAuditLogEnabled(String callingPackage) {
+        if (!mHasFeature) {
+            return false;
+        }
+
+        if (!securityLogV2Enabled()) {
+            throw new UnsupportedOperationException("Audit log not enabled");
+        }
+
+        final CallerIdentity caller = getCallerIdentity(callingPackage);
+        EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
+                null /* admin */,
+                MANAGE_DEVICE_POLICY_AUDIT_LOGGING,
+                caller.getPackageName(),
+                caller.getUserId());
+
+        Boolean policy = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+                PolicyDefinition.AUDIT_LOGGING, admin);
+
+        return Boolean.TRUE.equals(policy);
+    }
+
+    @Override
+    public void setAuditLogEventsCallback(String callingPackage, IAuditLogEventsCallback callback) {
+        if (!mHasFeature) {
+            return;
+        }
+
+        final CallerIdentity caller = getCallerIdentity(callingPackage);
+        EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
+                null /* admin */,
+                MANAGE_DEVICE_POLICY_AUDIT_LOGGING,
+                caller.getPackageName(),
+                caller.getUserId());
+
+        Boolean policy = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+                PolicyDefinition.AUDIT_LOGGING, admin);
+
+        if (!Boolean.TRUE.equals(policy)) {
+            throw new IllegalStateException(
+                    "Managing app has to enable audit log before setting events callback");
+        }
+
+        mSecurityLogMonitor.setAuditLogEventsCallback(caller.getUid(), callback);
+    }
+
+    @Override
     public long forceSecurityLogs() {
         Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
                         || hasCallingOrSelfPermission(permission.FORCE_DEVICE_POLICY_MANAGER_LOGS),
@@ -21984,6 +22099,20 @@
     }
 
     @Override
+    public boolean isTheftDetectionTriggered(String callerPackageName) {
+        final CallerIdentity caller = getCallerIdentity(callerPackageName);
+        if (!android.app.admin.flags.Flags.deviceTheftImplEnabled()) {
+            return false;
+        }
+        enforcePermission(MANAGE_DEVICE_POLICY_THEFT_DETECTION, caller.getPackageName(),
+                caller.getUserId());
+
+        //STOPSHIP: replace 1<<9 with
+        // LockPatternUtils.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST once ag/26042068 lands
+        return 0 != (mLockPatternUtils.getStrongAuthForUser(caller.getUserId()) & (1 << 9));
+    }
+
+    @Override
     public void setWifiSsidPolicy(String callerPackageName, WifiSsidPolicy policy) {
         CallerIdentity caller;
 
@@ -22424,14 +22553,6 @@
         });
     }
 
-    // Permission that will need to be created in V.
-    private static final String MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL =
-            "manage_device_policy_block_uninstall";
-    private static final String MANAGE_DEVICE_POLICY_CAMERA_TOGGLE =
-            "manage_device_policy_camera_toggle";
-    private static final String MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE =
-            "manage_device_policy_microphone_toggle";
-
     // DPC types
     private static final int NOT_A_DPC = -1;
     private static final int DEFAULT_DEVICE_OWNER = 0;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 3474db3..1247f9002 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -141,6 +141,13 @@
             PolicyEnforcerCallbacks::enforceSecurityLogging,
             new BooleanPolicySerializer());
 
+    static PolicyDefinition<Boolean> AUDIT_LOGGING = new PolicyDefinition<>(
+            new NoArgsPolicyKey(DevicePolicyIdentifiers.AUDIT_LOGGING_POLICY),
+            TRUE_MORE_RESTRICTIVE,
+            POLICY_FLAG_GLOBAL_ONLY_POLICY,
+            PolicyEnforcerCallbacks::enforceAuditLogging,
+            new BooleanPolicySerializer());
+
     static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
             new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
             new TopPriority<>(List.of(
@@ -365,6 +372,8 @@
                 GENERIC_PERMISSION_GRANT);
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.SECURITY_LOGGING_POLICY,
                 SECURITY_LOGGING);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUDIT_LOGGING_POLICY,
+                AUDIT_LOGGING);
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK);
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
                 USER_CONTROLLED_DISABLED_PACKAGES);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 4aaefa6..54242ab 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -136,6 +136,14 @@
         return true;
     }
 
+    static boolean enforceAuditLogging(
+            @Nullable Boolean value, @NonNull Context context, int userId,
+            @NonNull PolicyKey policyKey) {
+        final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
+        dpmi.enforceAuditLoggingPolicy(Boolean.TRUE.equals(value));
+        return true;
+    }
+
     static boolean setLockTask(
             @Nullable LockTaskPolicy policy, @NonNull Context context, int userId) {
         List<String> packages = Collections.emptyList();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index 7a4454b..02f3918 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -16,22 +16,32 @@
 
 package com.android.server.devicepolicy;
 
+import static android.app.admin.flags.Flags.securityLogV2Enabled;
+
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
 import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.IAuditLogEventsCallback;
 import android.app.admin.SecurityLog;
 import android.app.admin.SecurityLog.SecurityEvent;
+import android.os.Handler;
+import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.utils.Slogf;
 
 import java.io.IOException;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -53,15 +63,11 @@
 
     private int mEnabledUser;
 
-    SecurityLogMonitor(DevicePolicyManagerService service) {
-        this(service, 0 /* id */);
-    }
-
-    @VisibleForTesting
-    SecurityLogMonitor(DevicePolicyManagerService service, long id) {
+    SecurityLogMonitor(DevicePolicyManagerService service, Handler handler) {
         mService = service;
-        mId = id;
+        mId = 0;
         mLastForceNanos = System.nanoTime();
+        mHandler = handler;
     }
 
     private static final boolean DEBUG = false;  // STOPSHIP if true.
@@ -118,6 +124,9 @@
     @GuardedBy("mLock")
     private boolean mCriticalLevelLogged = false;
 
+    private boolean mLegacyLogEnabled;
+    private boolean mAuditLogEnabled;
+
     /**
      * Last events fetched from log to check for overlap between batches. We can leave it empty if
      * we are sure there will be no overlap anymore, e.g. when we get empty batch.
@@ -143,6 +152,40 @@
     private long mLastForceNanos = 0;
 
     /**
+     * Handler shared with DPMS.
+     */
+    private final Handler mHandler;
+
+    /**
+     * Oldest events get purged from audit log buffer if total number exceeds this value.
+     */
+    private static final int MAX_AUDIT_LOG_EVENTS = 10000;
+    /**
+     * Events older than this get purged from audit log buffer.
+     */
+    private static final long MAX_AUDIT_LOG_EVENT_AGE_NS = TimeUnit.HOURS.toNanos(8);
+
+    /**
+     * Audit log callbacks keyed by UID. The code should maintain the following invariant: all
+     * callbacks in this map have received (or are scheduled to receive) all events in
+     * mAuditLogEventsBuffer. To ensure this, before a callback is put into this map, it must be
+     * scheduled to receive all the events in the buffer, and conversely, before a new chunk of
+     * events is added to the buffer, it must be scheduled to be sent to all callbacks already in
+     * this list. All scheduling should happen on mHandler, so that they aren't reordered, and
+     * while holding the lock. This ensures that no callback misses an event or receives a duplicate
+     * or out of order events.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<IAuditLogEventsCallback> mAuditLogCallbacks = new SparseArray<>();
+
+    /**
+     * Audit log event buffer. It is shrunk automatically whenever either there are too many events
+     * or the oldest one is too old.
+     */
+    @GuardedBy("mLock")
+    private final ArrayDeque<SecurityEvent> mAuditLogEventBuffer = new ArrayDeque<>();
+
+    /**
      * Start security logging.
      *
      * @param enabledUser which user logging is enabled on, or USER_ALL to enable logging for all
@@ -154,18 +197,8 @@
         mLock.lock();
         try {
             if (mMonitorThread == null) {
-                mPendingLogs = new ArrayList<>();
-                mCriticalLevelLogged = false;
-                mId = 0;
-                mAllowedToRetrieve = false;
-                mNextAllowedRetrievalTimeMillis = -1;
-                mPaused = false;
-
-                mMonitorThread = new Thread(this);
-                mMonitorThread.start();
-
-                SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
-                Slog.i(TAG, "Security log monitor thread started");
+                resetLegacyBufferLocked();
+                startMonitorThreadLocked();
             } else {
                 Slog.i(TAG, "Security log monitor thread is already running");
             }
@@ -176,29 +209,82 @@
 
     void stop() {
         Slog.i(TAG, "Stopping security logging.");
-        SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STOPPED);
         mLock.lock();
         try {
             if (mMonitorThread != null) {
-                mMonitorThread.interrupt();
-                try {
-                    mMonitorThread.join(TimeUnit.SECONDS.toMillis(5));
-                } catch (InterruptedException e) {
-                    Log.e(TAG, "Interrupted while waiting for thread to stop", e);
-                }
-                // Reset state and clear buffer
-                mPendingLogs = new ArrayList<>();
-                mId = 0;
-                mAllowedToRetrieve = false;
-                mNextAllowedRetrievalTimeMillis = -1;
-                mPaused = false;
-                mMonitorThread = null;
+                stopMonitorThreadLocked();
+                resetLegacyBufferLocked();
             }
         } finally {
             mLock.unlock();
         }
     }
 
+    void setLoggingParams(int enabledUser, boolean legacyLogEnabled, boolean auditLogEnabled) {
+        Slogf.i(TAG, "Setting logging params, user = %d -> %d, legacy: %b -> %b, audit %b -> %b",
+                mEnabledUser, enabledUser, mLegacyLogEnabled, legacyLogEnabled, mAuditLogEnabled,
+                auditLogEnabled);
+        mLock.lock();
+        try {
+            mEnabledUser = enabledUser;
+            if (mMonitorThread == null && (legacyLogEnabled || auditLogEnabled)) {
+                startMonitorThreadLocked();
+            } else if (mMonitorThread != null && !legacyLogEnabled && !auditLogEnabled) {
+                stopMonitorThreadLocked();
+            }
+
+            if (mLegacyLogEnabled != legacyLogEnabled) {
+                resetLegacyBufferLocked();
+                mLegacyLogEnabled = legacyLogEnabled;
+            }
+
+            if (mAuditLogEnabled != auditLogEnabled) {
+                resetAuditBufferLocked();
+                mAuditLogEnabled = auditLogEnabled;
+            }
+        } finally {
+            mLock.unlock();
+        }
+
+    }
+
+    @GuardedBy("mLock")
+    private void startMonitorThreadLocked() {
+        mId = 0;
+        mPaused = false;
+        mMonitorThread = new Thread(this);
+        mMonitorThread.start();
+        SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
+        Slog.i(TAG, "Security log monitor thread started");
+    }
+
+    @GuardedBy("mLock")
+    private void stopMonitorThreadLocked() {
+        mMonitorThread.interrupt();
+        try {
+            mMonitorThread.join(TimeUnit.SECONDS.toMillis(5));
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while waiting for thread to stop", e);
+        }
+        mMonitorThread = null;
+        SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STOPPED);
+    }
+
+    @GuardedBy("mLock")
+    private void resetLegacyBufferLocked() {
+        mPendingLogs = new ArrayList<>();
+        mCriticalLevelLogged = false;
+        mAllowedToRetrieve = false;
+        mNextAllowedRetrievalTimeMillis = -1;
+        Slog.i(TAG, "Legacy buffer reset.");
+    }
+
+    @GuardedBy("mLock")
+    private void resetAuditBufferLocked() {
+        mAuditLogEventBuffer.clear();
+        mAuditLogCallbacks.clear();
+    }
+
     /**
      * If logs are being collected, keep collecting them but stop notifying the device owner that
      * new logs are available (since they cannot be retrieved).
@@ -338,8 +424,7 @@
      */
     @GuardedBy("mLock")
     private void mergeBatchLocked(final ArrayList<SecurityEvent> newLogs) {
-        // Reserve capacity so that copying doesn't occur.
-        mPendingLogs.ensureCapacity(mPendingLogs.size() + newLogs.size());
+        List<SecurityEvent> dedupedLogs = new ArrayList<>();
         // Run through the first events of the batch to check if there is an overlap with previous
         // batch and if so, skip overlapping events. Events are sorted by timestamp, so we can
         // compare it in linear time by advancing two pointers, one for each batch.
@@ -358,8 +443,7 @@
             if (lastNanos > currentNanos) {
                 // New event older than the last we've seen so far, must be due to reordering.
                 if (DEBUG) Slog.d(TAG, "New event in the overlap: " + currentNanos);
-                assignLogId(curEvent);
-                mPendingLogs.add(curEvent);
+                dedupedLogs.add(curEvent);
                 curPos++;
             } else if (lastNanos < currentNanos) {
                 if (DEBUG) Slog.d(TAG, "Event disappeared from the overlap: " + lastNanos);
@@ -371,8 +455,7 @@
                     if (DEBUG) Slog.d(TAG, "Skipped dup event with timestamp: " + lastNanos);
                 } else {
                     // Wow, what a coincidence, or probably the clock is too coarse.
-                    assignLogId(curEvent);
-                    mPendingLogs.add(curEvent);
+                    dedupedLogs.add(curEvent);
                     if (DEBUG) Slog.d(TAG, "Event timestamp collision: " + lastNanos);
                 }
                 lastPos++;
@@ -380,12 +463,23 @@
             }
         }
         // Assign an id to the new logs, after the overlap with mLastEvents.
-        List<SecurityEvent> idLogs = newLogs.subList(curPos, newLogs.size());
-        for (SecurityEvent event : idLogs) {
+        dedupedLogs.addAll(newLogs.subList(curPos, newLogs.size()));
+        for (SecurityEvent event : dedupedLogs) {
             assignLogId(event);
         }
+
+        if (!securityLogV2Enabled() || mLegacyLogEnabled) {
+            addToLegacyBuffer(dedupedLogs);
+        }
+
+        if (securityLogV2Enabled() && mAuditLogEnabled) {
+            addAuditLogEvents(dedupedLogs);
+        }
+    }
+
+    private void addToLegacyBuffer(List<SecurityEvent> dedupedLogs) {
         // Save the rest of the new batch.
-        mPendingLogs.addAll(idLogs);
+        mPendingLogs.addAll(dedupedLogs);
 
         checkCriticalLevel();
 
@@ -453,7 +547,10 @@
 
                 saveLastEvents(newLogs);
                 newLogs.clear();
-                notifyDeviceOwnerOrProfileOwnerIfNeeded(force);
+
+                if (!securityLogV2Enabled() || mLegacyLogEnabled) {
+                    notifyDeviceOwnerOrProfileOwnerIfNeeded(force);
+                }
             } catch (IOException e) {
                 Log.e(TAG, "Failed to read security log", e);
             } catch (InterruptedException e) {
@@ -532,4 +629,121 @@
             return 0;
         }
     }
+
+    public void setAuditLogEventsCallback(int uid, IAuditLogEventsCallback callback) {
+        mLock.lock();
+        try {
+            if (callback == null) {
+                mAuditLogCallbacks.remove(uid);
+                Slogf.i(TAG, "Cleared audit log callback for UID %d", uid);
+                return;
+            }
+            // Create a copy while holding the lock, so that that new events are not added
+            // resulting in duplicates.
+            final List<SecurityEvent> events = new ArrayList<>(mAuditLogEventBuffer);
+            scheduleSendAuditLogs(uid, callback, events);
+            mAuditLogCallbacks.append(uid, callback);
+        } finally {
+            mLock.unlock();
+        }
+        Slogf.i(TAG, "Set audit log callback for UID %d", uid);
+    }
+
+    private void addAuditLogEvents(List<SecurityEvent> events) {
+        mLock.lock();
+        try {
+            if (mPaused) {
+                // TODO: maybe we need to stash the logs in some temp buffer wile paused so that
+                // they can be accessed after affiliation is fixed.
+                return;
+            }
+            if (!events.isEmpty()) {
+                for (int i = 0; i < mAuditLogCallbacks.size(); i++) {
+                    final int uid = mAuditLogCallbacks.keyAt(i);
+                    scheduleSendAuditLogs(uid, mAuditLogCallbacks.valueAt(i), events);
+                }
+            }
+            if (DEBUG) {
+                Slogf.d(TAG, "Adding audit %d events to % already present in the buffer",
+                        events.size(), mAuditLogEventBuffer.size());
+            }
+            mAuditLogEventBuffer.addAll(events);
+            trimAuditLogBufferLocked();
+            if (DEBUG) {
+                Slogf.d(TAG, "Audit event buffer size after trimming: %d",
+                        mAuditLogEventBuffer.size());
+            }
+        } finally {
+            mLock.unlock();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void trimAuditLogBufferLocked() {
+        long nowNanos = TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis());
+
+        final Iterator<SecurityEvent> iterator = mAuditLogEventBuffer.iterator();
+        while (iterator.hasNext()) {
+            final SecurityEvent event = iterator.next();
+            if (mAuditLogEventBuffer.size() <= MAX_AUDIT_LOG_EVENTS
+                    && nowNanos - event.getTimeNanos() <= MAX_AUDIT_LOG_EVENT_AGE_NS) {
+                break;
+            }
+
+            iterator.remove();
+        }
+    }
+
+    private void scheduleSendAuditLogs(
+            int uid, IAuditLogEventsCallback callback, List<SecurityEvent> events) {
+        if (DEBUG) {
+            Slogf.d(TAG, "Scheduling to send %d audit log events to UID %d", events.size(), uid);
+        }
+        mHandler.post(() -> sendAuditLogs(uid, callback, events));
+    }
+
+    private void sendAuditLogs(
+            int uid, IAuditLogEventsCallback callback, List<SecurityEvent> events) {
+        try {
+            final int size = events.size();
+            if (DEBUG) {
+                Slogf.d(TAG, "Sending %d audit log events to UID %d", size, uid);
+            }
+            callback.onNewAuditLogEvents(events);
+            if (DEBUG) {
+                Slogf.d(TAG, "Sent %d audit log events to UID %d", size, uid);
+            }
+        } catch (RemoteException e) {
+            Slogf.e(TAG, e, "Failed to invoke audit log callback for UID %d", uid);
+            removeAuditLogEventsCallbackIfDead(uid, callback);
+        }
+    }
+
+    private void removeAuditLogEventsCallbackIfDead(int uid, IAuditLogEventsCallback callback) {
+        final IBinder binder = callback.asBinder();
+        if (binder.isBinderAlive()) {
+            Slog.i(TAG, "Callback binder is still alive, not removing.");
+            return;
+        }
+
+        mLock.lock();
+        try {
+            int index = mAuditLogCallbacks.indexOfKey(uid);
+            if (index < 0) {
+                Slogf.i(TAG, "Callback not registered for UID %d, nothing to remove", uid);
+                return;
+            }
+
+            final IBinder storedBinder = mAuditLogCallbacks.valueAt(index).asBinder();
+            if (!storedBinder.equals(binder)) {
+                Slogf.i(TAG, "Callback is already replaced for UID %d, not removing", uid);
+                return;
+            }
+
+            Slogf.i(TAG, "Removing callback for UID %d", uid);
+            mAuditLogCallbacks.removeAt(index);
+        } finally {
+            mLock.unlock();
+        }
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 14e4481..ee758db 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -107,6 +107,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockSettingsInternal;
+import com.android.server.adaptiveauth.AdaptiveAuthService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.appbinding.AppBindingService;
 import com.android.server.appop.AppOpMigrationHelper;
@@ -2615,6 +2616,12 @@
             mSystemServiceManager.startService(AuthService.class);
             t.traceEnd();
 
+            if (android.adaptiveauth.Flags.enableAdaptiveAuth()) {
+                t.traceBegin("StartAdaptiveAuthService");
+                mSystemServiceManager.startService(AdaptiveAuthService.class);
+                t.traceEnd();
+            }
+
             if (!isWatch) {
                 // We don't run this on watches as there are no plans to use the data logged
                 // on watch devices.
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 5588276..cb3ee73 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -46,6 +46,7 @@
 import com.android.server.pm.parsing.PackageInfoUtils
 import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageState
+import libcore.util.EmptyArray
 
 class AppIdPermissionPolicy : SchemePolicy() {
     private val persistence = AppIdPermissionPersistence()
@@ -73,40 +74,42 @@
     }
 
     override fun MutateStateScope.onInitialized() {
-        newState.externalState.configPermissions.forEach { (permissionName, permissionEntry) ->
-            val oldPermission = newState.systemState.permissions[permissionName]
-            val newPermission =
-                if (oldPermission != null) {
-                    if (permissionEntry.gids != null) {
-                        oldPermission.copy(
-                            gids = permissionEntry.gids,
-                            areGidsPerUser = permissionEntry.perUser
-                        )
-                    } else {
-                        return@forEach
-                    }
-                } else {
-                    @Suppress("DEPRECATION")
-                    val permissionInfo =
-                        PermissionInfo().apply {
-                            name = permissionName
-                            packageName = PLATFORM_PACKAGE_NAME
-                            protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
+        if (!Flags.newPermissionGidEnabled()) {
+            newState.externalState.configPermissions.forEach { (permissionName, permissionEntry) ->
+                val oldPermission = newState.systemState.permissions[permissionName]
+                val newPermission =
+                    if (oldPermission != null) {
+                        if (permissionEntry.gids != null) {
+                            oldPermission.copy(
+                                gids = permissionEntry.gids,
+                                areGidsPerUser = permissionEntry.perUser
+                            )
+                        } else {
+                            return@forEach
                         }
-                    if (permissionEntry.gids != null) {
-                        Permission(
-                            permissionInfo,
-                            false,
-                            Permission.TYPE_CONFIG,
-                            0,
-                            permissionEntry.gids,
-                            permissionEntry.perUser
-                        )
                     } else {
-                        Permission(permissionInfo, false, Permission.TYPE_CONFIG, 0)
+                        @Suppress("DEPRECATION")
+                        val permissionInfo =
+                            PermissionInfo().apply {
+                                name = permissionName
+                                packageName = PLATFORM_PACKAGE_NAME
+                                protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
+                            }
+                        if (permissionEntry.gids != null) {
+                            Permission(
+                                permissionInfo,
+                                false,
+                                Permission.TYPE_CONFIG,
+                                0,
+                                permissionEntry.gids,
+                                permissionEntry.perUser
+                            )
+                        } else {
+                            Permission(permissionInfo, false, Permission.TYPE_CONFIG, 0)
+                        }
                     }
-                }
-            newState.mutateSystemState().mutatePermissions()[permissionName] = newPermission
+                newState.mutateSystemState().mutatePermissions()[permissionName] = newPermission
+            }
         }
     }
 
@@ -459,7 +462,7 @@
                 )
                 return@forEachIndexed
             }
-            val newPermission =
+            var newPermission =
                 if (oldPermission != null && newPackageName != oldPermission.packageName) {
                     val oldPackageName = oldPermission.packageName
                     // Only allow system apps to redefine non-system permissions.
@@ -582,6 +585,24 @@
                         )
                     }
                 }
+            if (Flags.newPermissionGidEnabled()) {
+                var gids = EmptyArray.INT
+                var areGidsPerUser = false
+                if (!parsedPermission.isTree && packageState.isSystem) {
+                    newState.externalState.configPermissions[permissionName]?.let {
+                        gids = it.gids
+                        areGidsPerUser = it.perUser
+                    }
+                }
+                newPermission = Permission(
+                    newPermissionInfo,
+                    true,
+                    Permission.TYPE_MANIFEST,
+                    packageState.appId,
+                    gids,
+                    areGidsPerUser
+                )
+            }
 
             if (parsedPermission.isTree) {
                 newState.mutateSystemState().mutatePermissionTrees()[permissionName] = newPermission
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 67f66de..0704c8f 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -466,7 +466,7 @@
         return size
     }
 
-    override fun checkUidPermission(uid: Int, permissionName: String, deviceId: Int): Int {
+    override fun checkUidPermission(uid: Int, permissionName: String, deviceId: String): Int {
         val userId = UserHandle.getUserId(uid)
         if (!userManagerInternal.exists(userId)) {
             return PackageManager.PERMISSION_DENIED
@@ -489,15 +489,9 @@
                 return PackageManager.PERMISSION_DENIED
             }
 
-            val persistentDeviceId = getPersistentDeviceId(deviceId)
-            if (persistentDeviceId == null) {
-                Slog.e(LOG_TAG, "Cannot find persistent device id for $deviceId.")
-                return PackageManager.PERMISSION_DENIED
-            }
-
             val isPermissionGranted =
                 service.getState {
-                    isPermissionGranted(packageState, userId, permissionName, persistentDeviceId)
+                    isPermissionGranted(packageState, userId, permissionName, deviceId)
                 }
             return if (isPermissionGranted) {
                 PackageManager.PERMISSION_GRANTED
@@ -531,7 +525,7 @@
     override fun checkPermission(
         packageName: String,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         userId: Int
     ): Int {
         if (!userManagerInternal.exists(userId)) {
@@ -545,9 +539,7 @@
                 ?: return PackageManager.PERMISSION_DENIED
 
         val isPermissionGranted =
-            service.getState {
-                isPermissionGranted(packageState, userId, permissionName, persistentDeviceId)
-            }
+            service.getState { isPermissionGranted(packageState, userId, permissionName, deviceId) }
         return if (isPermissionGranted) {
             PackageManager.PERMISSION_GRANTED
         } else {
@@ -565,21 +557,13 @@
         packageState: PackageState,
         userId: Int,
         permissionName: String,
-        persistentDeviceId: String
+        deviceId: String
     ): Boolean {
         val appId = packageState.appId
         // Note that instant apps can't have shared UIDs, so we only need to check the current
         // package state.
         val isInstantApp = packageState.getUserStateOrDefault(userId).isInstantApp
-        if (
-            isSinglePermissionGranted(
-                appId,
-                userId,
-                isInstantApp,
-                permissionName,
-                persistentDeviceId
-            )
-        ) {
+        if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName, deviceId)) {
             return true
         }
 
@@ -591,7 +575,7 @@
                     userId,
                     isInstantApp,
                     fullerPermissionName,
-                    persistentDeviceId
+                    deviceId
                 )
         ) {
             return true
@@ -606,9 +590,9 @@
         userId: Int,
         isInstantApp: Boolean,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
     ): Boolean {
-        val flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId)
+        val flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
         if (!PermissionFlags.isPermissionGranted(flags)) {
             return false
         }
@@ -689,22 +673,16 @@
     override fun grantRuntimePermission(
         packageName: String,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         userId: Int
     ) {
-        setRuntimePermissionGranted(
-            packageName,
-            userId,
-            permissionName,
-            persistentDeviceId,
-            isGranted = true
-        )
+        setRuntimePermissionGranted(packageName, userId, permissionName, deviceId, isGranted = true)
     }
 
     override fun revokeRuntimePermission(
         packageName: String,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         userId: Int,
         reason: String?
     ) {
@@ -712,7 +690,7 @@
             packageName,
             userId,
             permissionName,
-            persistentDeviceId,
+            deviceId,
             isGranted = false,
             revokeReason = reason
         )
@@ -740,7 +718,7 @@
         packageName: String,
         userId: Int,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         isGranted: Boolean,
         skipKillUid: Boolean = false,
         revokeReason: String? = null
@@ -765,7 +743,7 @@
                     (if (isGranted) "" else "skipKillUid = $skipKillUid, reason = $revokeReason") +
                     ", userId = $userId," +
                     " callingUid = $callingUidName ($callingUid))," +
-                    " persistentDeviceId = $persistentDeviceId",
+                    " deviceId = $deviceId",
                 RuntimeException()
             )
         }
@@ -835,7 +813,7 @@
                 packageState,
                 userId,
                 permissionName,
-                persistentDeviceId,
+                deviceId,
                 isGranted,
                 canManageRolePermission,
                 overridePolicyFixed,
@@ -923,7 +901,7 @@
         packageState: PackageState,
         userId: Int,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         isGranted: Boolean,
         canManageRolePermission: Boolean,
         overridePolicyFixed: Boolean,
@@ -982,8 +960,7 @@
         }
 
         val appId = packageState.appId
-        val oldFlags =
-            getPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId)
+        val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
 
         if (permissionName !in androidPackage.requestedPermissions && oldFlags == 0) {
             if (reportError) {
@@ -1055,7 +1032,7 @@
             return
         }
 
-        setPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId, newFlags)
+        setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
 
         if (permission.isRuntime) {
             val action =
@@ -1089,7 +1066,7 @@
     override fun getPermissionFlags(
         packageName: String,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         userId: Int,
     ): Int {
         if (!userManagerInternal.exists(userId)) {
@@ -1125,12 +1102,7 @@
             }
 
             val flags =
-                getPermissionFlagsWithPolicy(
-                    packageState.appId,
-                    userId,
-                    permissionName,
-                    persistentDeviceId
-                )
+                getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
 
             return PermissionFlags.toApiFlags(flags)
         }
@@ -1138,7 +1110,7 @@
 
     override fun getAllPermissionStates(
         packageName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         userId: Int
     ): Map<String, PermissionState> {
         if (!userManagerInternal.exists(userId)) {
@@ -1165,14 +1137,15 @@
 
         val permissionFlagsMap =
             service.getState {
-                if (persistentDeviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT) {
+                if (deviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT) {
                     with(policy) { getAllPermissionFlags(packageState.appId, userId) }
                 } else {
                     with(devicePolicy) {
-                        getAllPermissionFlags(packageState.appId, persistentDeviceId, userId)
+                        getAllPermissionFlags(packageState.appId, deviceId, userId)
                     }
                 }
-            } ?: return emptyMap()
+            }
+                ?: return emptyMap()
 
         val permissionStates = ArrayMap<String, PermissionState>()
         permissionFlagsMap.forEachIndexed { _, permissionName, flags ->
@@ -1186,7 +1159,7 @@
     override fun isPermissionRevokedByPolicy(
         packageName: String,
         permissionName: String,
-        deviceId: Int,
+        deviceId: String,
         userId: Int
     ): Boolean {
         if (!userManagerInternal.exists(userId)) {
@@ -1207,24 +1180,13 @@
             }
                 ?: return false
 
-        val persistentDeviceId = getPersistentDeviceId(deviceId)
-        if (persistentDeviceId == null) {
-            Slog.w(LOG_TAG, "Cannot find persistent device Id for $deviceId")
-            return false
-        }
-
         service.getState {
-            if (isPermissionGranted(packageState, userId, permissionName, persistentDeviceId)) {
+            if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
                 return false
             }
 
             val flags =
-                getPermissionFlagsWithPolicy(
-                    packageState.appId,
-                    userId,
-                    permissionName,
-                    persistentDeviceId
-                )
+                getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
 
             return flags.hasBits(PermissionFlags.POLICY_FIXED)
         }
@@ -1248,7 +1210,7 @@
     override fun shouldShowRequestPermissionRationale(
         packageName: String,
         permissionName: String,
-        deviceId: Int,
+        deviceId: String,
         userId: Int,
     ): Boolean {
         if (!userManagerInternal.exists(userId)) {
@@ -1274,19 +1236,13 @@
             return false
         }
 
-        val persistentDeviceId = getPersistentDeviceId(deviceId)
-        if (persistentDeviceId == null) {
-            Slog.w(LOG_TAG, "Cannot find persistent device Id for $deviceId")
-            return false
-        }
-
         val flags: Int
         service.getState {
-            if (isPermissionGranted(packageState, userId, permissionName, persistentDeviceId)) {
+            if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
                 return false
             }
 
-            flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId)
+            flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
         }
         if (flags.hasAnyBit(UNREQUESTABLE_MASK)) {
             return false
@@ -1325,7 +1281,7 @@
         flagMask: Int,
         flagValues: Int,
         enforceAdjustPolicyPermission: Boolean,
-        persistentDeviceId: String,
+        deviceId: String,
         userId: Int
     ) {
         val callingUid = Binder.getCallingUid()
@@ -1351,7 +1307,7 @@
                 "updatePermissionFlags(packageName = $packageName," +
                     " permissionName = $permissionName, flagMask = $flagMaskString," +
                     " flagValues = $flagValuesString, userId = $userId," +
-                    " persistentDeviceId = $persistentDeviceId," +
+                    " deviceId = $deviceId," +
                     " callingUid = $callingUidName ($callingUid))",
                 RuntimeException()
             )
@@ -1441,7 +1397,7 @@
                 appId,
                 userId,
                 permissionName,
-                persistentDeviceId,
+                deviceId,
                 flagMask,
                 flagValues,
                 canUpdateSystemFlags,
@@ -1527,7 +1483,7 @@
         appId: Int,
         userId: Int,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         flagMask: Int,
         flagValues: Int,
         canUpdateSystemFlags: Boolean,
@@ -1561,8 +1517,7 @@
             return
         }
 
-        val oldFlags =
-            getPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId)
+        val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
         if (!isPermissionRequested && oldFlags == 0) {
             Slog.w(
                 LOG_TAG,
@@ -1573,7 +1528,7 @@
         }
 
         val newFlags = PermissionFlags.updateFlags(permission, oldFlags, flagMask, flagValues)
-        setPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId, newFlags)
+        setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
     }
 
     override fun getAllowlistedRestrictedPermissions(
@@ -1648,11 +1603,11 @@
         appId: Int,
         userId: Int,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
     ): Int {
         return if (
             !Flags.deviceAwarePermissionApisEnabled() ||
-                persistentDeviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
+                deviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
         ) {
             with(policy) { getPermissionFlags(appId, userId, permissionName) }
         } else {
@@ -1664,9 +1619,7 @@
                 )
                 return with(policy) { getPermissionFlags(appId, userId, permissionName) }
             }
-            with(devicePolicy) {
-                getPermissionFlags(appId, persistentDeviceId, userId, permissionName)
-            }
+            with(devicePolicy) { getPermissionFlags(appId, deviceId, userId, permissionName) }
         }
     }
 
@@ -1674,12 +1627,12 @@
         appId: Int,
         userId: Int,
         permissionName: String,
-        persistentDeviceId: String,
+        deviceId: String,
         flags: Int
     ): Boolean {
         return if (
             !Flags.deviceAwarePermissionApisEnabled() ||
-                persistentDeviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
+                deviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
         ) {
             with(policy) { setPermissionFlags(appId, userId, permissionName, flags) }
         } else {
@@ -1693,23 +1646,11 @@
             }
 
             with(devicePolicy) {
-                setPermissionFlags(appId, persistentDeviceId, userId, permissionName, flags)
+                setPermissionFlags(appId, deviceId, userId, permissionName, flags)
             }
         }
     }
 
-    private fun getPersistentDeviceId(deviceId: Int): String? {
-        if (deviceId == Context.DEVICE_ID_DEFAULT) {
-            return VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
-        }
-
-        if (virtualDeviceManagerInternal == null) {
-            virtualDeviceManagerInternal =
-                LocalServices.getService(VirtualDeviceManagerInternal::class.java)
-        }
-        return virtualDeviceManagerInternal?.getPersistentIdForDevice(deviceId)
-    }
-
     /**
      * This method does not enforce checks on the caller, should only be called after required
      * checks.
@@ -2270,9 +2211,9 @@
 
                     userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
                         _,
-                        persistentDeviceId,
+                        deviceId,
                         devicePermissionFlags ->
-                        println("Permissions (Device $persistentDeviceId):")
+                        println("Permissions (Device $deviceId):")
                         withIndent {
                             devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
                                 val isGranted = PermissionFlags.isPermissionGranted(flags)
@@ -2415,9 +2356,8 @@
                 with(devicePolicy) { trimDevicePermissionStates(persistentDeviceIds) }
             }
         }
-        virtualDeviceManagerInternal?.registerPersistentDeviceIdRemovedListener { persistentDeviceId
-            ->
-            service.mutateState { with(devicePolicy) { onDeviceIdRemoved(persistentDeviceId) } }
+        virtualDeviceManagerInternal?.registerPersistentDeviceIdRemovedListener { deviceId ->
+            service.mutateState { with(devicePolicy) { onDeviceIdRemoved(deviceId) } }
         }
 
         permissionControllerManager =
@@ -2764,7 +2704,7 @@
         override fun onDevicePermissionFlagsChanged(
             appId: Int,
             userId: Int,
-            persistentDeviceId: String,
+            deviceId: String,
             permissionName: String,
             oldFlags: Int,
             newFlags: Int
@@ -2787,8 +2727,7 @@
                         permissionName in NOTIFICATIONS_PERMISSIONS &&
                             runtimePermissionRevokedUids.get(uid, true)
                 }
-                runtimePermissionChangedUidDevices.getOrPut(uid) { mutableSetOf() } +=
-                    persistentDeviceId
+                runtimePermissionChangedUidDevices.getOrPut(uid) { mutableSetOf() } += deviceId
             }
 
             if (permission.hasGids && !wasPermissionGranted && isPermissionGranted) {
@@ -2803,8 +2742,8 @@
             }
 
             runtimePermissionChangedUidDevices.forEachIndexed { _, uid, persistentDeviceIds ->
-                persistentDeviceIds.forEach { persistentDeviceId ->
-                    onPermissionsChangeListeners.onPermissionsChanged(uid, persistentDeviceId)
+                persistentDeviceIds.forEach { deviceId ->
+                    onPermissionsChangeListeners.onPermissionsChanged(uid, deviceId)
                 }
             }
             runtimePermissionChangedUidDevices.clear()
@@ -2844,8 +2783,11 @@
 
         private fun isAppBackupAndRestoreRunning(uid: Int): Boolean {
             if (
-                checkUidPermission(uid, Manifest.permission.BACKUP, Context.DEVICE_ID_DEFAULT) !=
-                    PackageManager.PERMISSION_GRANTED
+                checkUidPermission(
+                    uid,
+                    Manifest.permission.BACKUP,
+                    VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
+                ) != PackageManager.PERMISSION_GRANTED
             ) {
                 return false
             }
@@ -2879,16 +2821,16 @@
             when (msg.what) {
                 MSG_ON_PERMISSIONS_CHANGED -> {
                     val uid = msg.arg1
-                    val persistentDeviceId = msg.obj as String
-                    handleOnPermissionsChanged(uid, persistentDeviceId)
+                    val deviceId = msg.obj as String
+                    handleOnPermissionsChanged(uid, deviceId)
                 }
             }
         }
 
-        private fun handleOnPermissionsChanged(uid: Int, persistentDeviceId: String) {
+        private fun handleOnPermissionsChanged(uid: Int, deviceId: String) {
             listeners.broadcast { listener ->
                 try {
-                    listener.onPermissionsChanged(uid, persistentDeviceId)
+                    listener.onPermissionsChanged(uid, deviceId)
                 } catch (e: RemoteException) {
                     Slog.e(LOG_TAG, "Error when calling OnPermissionsChangeListener", e)
                 }
@@ -2903,9 +2845,9 @@
             listeners.unregister(listener)
         }
 
-        fun onPermissionsChanged(uid: Int, persistentDeviceId: String) {
+        fun onPermissionsChanged(uid: Int, deviceId: String) {
             if (listeners.registeredCallbackCount > 0) {
-                obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, persistentDeviceId).sendToTarget()
+                obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, deviceId).sendToTarget()
             }
         }
 
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index bd86fe2..f15e533 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -32,8 +32,6 @@
         "androidx.test.runner",
         "truth",
         "Harrier",
-        "frameworks-base-testutils",
-        "services.core",
     ],
     platform_apis: true,
     certificate: "platform",
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
index c615823..4012d8e 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
@@ -16,36 +16,32 @@
 
 package com.android.server.pm.test.appenumeration;
 
+import static android.content.Context.MEDIA_PROJECTION_SERVICE;
+
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.MockitoAnnotations.initMocks;
-
-import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.pm.IPackageManager;
 import android.content.pm.ProviderInfo;
+import android.media.projection.IMediaProjectionManager;
 import android.media.projection.MediaProjectionManager;
 import android.os.Process;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.util.test.LocalServiceKeeperRule;
-import com.android.server.media.projection.MediaProjectionManagerService;
-
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -77,17 +73,9 @@
 
     private IPackageManager mIPackageManager;
 
-    @Rule
-    public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule();
-
-    @Mock private ActivityManagerInternal mActivityManagerInternal;
-
     @Before
     public void setup() {
-        initMocks(this);
         mIPackageManager = AppGlobals.getPackageManager();
-        mLocalServiceKeeperRule.overrideLocalService(ActivityManagerInternal.class,
-                mActivityManagerInternal);
     }
 
     @After
@@ -181,11 +169,11 @@
     public void mediaProjectionManager_createProjection_canSeeForceQueryable()
             throws Exception {
         installPackage(SHARED_USER_APK_PATH, true /* forceQueryable */);
-        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        final MediaProjectionManagerService mediaProjectionManager =
-                new MediaProjectionManagerService(context);
+        final IMediaProjectionManager mediaProjectionManager =
+                IMediaProjectionManager.Stub.asInterface(
+                        ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
 
-        assertThat(mediaProjectionManager.createProjectionInternal(0 /* uid */, TARGET_SHARED_USER,
+        assertThat(mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
                 MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */))
                 .isNotNull();
     }
@@ -193,13 +181,12 @@
     @Test
     public void mediaProjectionManager_createProjection_cannotSeeTarget() {
         installPackage(SHARED_USER_APK_PATH, false /* forceQueryable */);
-        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        final MediaProjectionManagerService mediaProjectionManager =
-                new MediaProjectionManagerService(context);
+        final IMediaProjectionManager mediaProjectionManager =
+                IMediaProjectionManager.Stub.asInterface(
+                        ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
 
         Assert.assertThrows(IllegalArgumentException.class,
-                () -> mediaProjectionManager.createProjectionInternal(0 /* uid */,
-                        TARGET_SHARED_USER,
+                () -> mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
                         MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */));
     }
 
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index cfe701f..d4b57f1 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -273,7 +273,8 @@
         AndroidPackage::hasRequestForegroundServiceExemption,
         AndroidPackage::hasRequestRawExternalStorageAccess,
         AndroidPackage::isUpdatableSystem,
-        AndroidPackage::getEmergencyInstaller
+        AndroidPackage::getEmergencyInstaller,
+        AndroidPackage::isAllowCrossUidActivitySwitchFromBelow,
     )
 
     override fun extraParams() = listOf(
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 d876dae..47928bc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -72,6 +72,8 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.AdditionalAnswers.answer;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
@@ -157,9 +159,11 @@
     private static final int MOCKAPP2_UID_OTHER = MOCKAPP2_UID + UserHandle.PER_USER_RANGE;
     private static final int MOCKAPP_ISOLATED_UID = Process.FIRST_ISOLATED_UID + 321;
     private static final String MOCKAPP_ISOLATED_PROCESSNAME = "isolated test #1";
+    private static final int MOCKAPP_SDK_SANDBOX_UID = Process.FIRST_SDK_SANDBOX_UID + 654;
+    private static final String MOCKAPP_SDK_SANDBOX_PROCESSNAME = "sandbox test #1";
 
     private static int sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ
-                                          + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+            + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
     private static Context sContext;
     private static PackageManagerInternal sPackageManagerInternal;
     private static ActivityManagerService sService;
@@ -271,7 +275,6 @@
 
     /**
      * Replace the process LRU with the given processes.
-     * @param apps
      */
     @SuppressWarnings("GuardedBy")
     private void setProcessesToLru(ProcessRecord... apps) {
@@ -660,7 +663,7 @@
             app.mState.setLastTopTime(nowUptime);
             // Simulate the system starting and binding to a service in the app.
             ServiceRecord s = bindService(app, system,
-                    null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+                    null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
             s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
             s.getConnections().clear();
             app.mServices.updateHasTopStartedAlmostPerceptibleServices();
@@ -682,7 +685,7 @@
             app.mState.setLastTopTime(nowUptime);
             // Simulate the system starting and binding to a service in the app.
             ServiceRecord s = bindService(app, system,
-                    null, Context.BIND_ALMOST_PERCEPTIBLE + 2, mock(IBinder.class));
+                    null, null, Context.BIND_ALMOST_PERCEPTIBLE + 2, mock(IBinder.class));
             s.lastTopAlmostPerceptibleBindRequestUptimeMs =
                     nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
             app.mServices.updateHasTopStartedAlmostPerceptibleServices();
@@ -704,7 +707,7 @@
             app.mState.setLastTopTime(nowUptime);
             // Simulate the system starting and binding to a service in the app.
             ServiceRecord s = bindService(app, system,
-                    null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+                    null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
             s.lastTopAlmostPerceptibleBindRequestUptimeMs =
                     nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
             s.getConnections().clear();
@@ -729,7 +732,7 @@
         system.mState.setHasTopUi(true);
         // Simulate the system starting and binding to a service in the app.
         ServiceRecord s = bindService(app, system,
-                null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+                null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(system, app);
 
@@ -901,7 +904,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        ServiceRecord s = bindService(app, client, null, Context.BIND_WAIVE_PRIORITY,
+        ServiceRecord s = bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY,
                 mock(IBinder.class));
         s.startRequested = true;
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -921,7 +924,7 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         client.mServices.setTreatLikeActivity(true);
-        bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
+        bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY
                 | Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -937,7 +940,7 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         IBinder binder = mock(IBinder.class);
-        ServiceRecord s = bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
+        ServiceRecord s = bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY
                 | Context.BIND_ADJUST_WITH_ACTIVITY | Context.BIND_IMPORTANT, binder);
         ConnectionRecord cr = s.getConnections().get(binder).get(0);
         setFieldValue(ConnectionRecord.class, cr, "activity",
@@ -955,7 +958,7 @@
     public void testUpdateOomAdj_DoOne_Service_Self() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
-        bindService(app, app, null, 0, mock(IBinder.class));
+        bindService(app, app, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app);
 
@@ -970,7 +973,7 @@
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         client.mServices.setTreatLikeActivity(true);
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
 
@@ -988,7 +991,8 @@
         doReturn(true).when(wpc).hasActivities();
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_ALLOW_OOM_MANAGEMENT, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_ALLOW_OOM_MANAGEMENT,
+                mock(IBinder.class));
         doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
         doReturn(client).when(sService).getTopApp();
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1005,7 +1009,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
         client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
         client.mState.setHasTopUi(true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1023,7 +1027,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_IMPORTANT, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_IMPORTANT, mock(IBinder.class));
         client.mServices.startExecutingService(mock(ServiceRecord.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1039,7 +1043,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
         doReturn(client).when(sService).getTopApp();
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1056,7 +1060,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
         client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1074,7 +1078,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
         client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1090,7 +1094,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1109,7 +1113,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
 
         // In order to trick OomAdjuster to think it has a short-service, we need this logic.
         ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
@@ -1172,8 +1176,8 @@
         ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
 
-        bindService(app1, pers, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
-        bindService(app2, app1, null, 0, mock(IBinder.class));
+        bindService(app1, pers, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
+        bindService(app2, app1, null, null, 0, mock(IBinder.class));
 
         updateOomAdj(pers, app1, app2);
 
@@ -1192,7 +1196,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
         BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
         backupTarget.app = client;
         doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
@@ -1218,7 +1222,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
         client.mState.setRunningRemoteAnimation(true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1233,7 +1237,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
         client.mState.setRunningRemoteAnimation(true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1248,7 +1252,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         client.mState.setHasOverlayUi(true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1264,7 +1268,7 @@
                     MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
             ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                     MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-            bindService(app, client, null,
+            bindService(app, client, null, null,
                     Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
                     mock(IBinder.class));
             client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
@@ -1283,7 +1287,7 @@
                     MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
             WindowProcessController wpc = client.getWindowProcessController();
             doReturn(true).when(wpc).isHeavyWeightProcess();
-            bindService(app, client, null,
+            bindService(app, client, null, null,
                     Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
                     mock(IBinder.class));
             client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
@@ -1301,7 +1305,7 @@
                     MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
             ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                     MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-            bindService(app, client, null,
+            bindService(app, client, null, null,
                     Context.BIND_ALMOST_PERCEPTIBLE,
                     mock(IBinder.class));
             client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
@@ -1320,7 +1324,7 @@
                     MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
             WindowProcessController wpc = client.getWindowProcessController();
             doReturn(true).when(wpc).isHeavyWeightProcess();
-            bindService(app, client, null,
+            bindService(app, client, null, null,
                     Context.BIND_ALMOST_PERCEPTIBLE,
                     mock(IBinder.class));
             client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
@@ -1341,7 +1345,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         client.mState.setRunningRemoteAnimation(true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1356,7 +1360,8 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_IMPORTANT_BACKGROUND, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_IMPORTANT_BACKGROUND,
+                mock(IBinder.class));
         client.mState.setHasOverlayUi(true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, app);
@@ -1496,10 +1501,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
         doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
         doReturn(client2).when(sService).getTopApp();
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1517,10 +1522,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(app, client2, null, 0, mock(IBinder.class));
+        bindService(app, client2, null, null, 0, mock(IBinder.class));
         client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, app);
@@ -1537,10 +1542,10 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
         client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, app);
@@ -1557,12 +1562,12 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
         client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(client2, app, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, null, 0, mock(IBinder.class));
 
         // Note: We add processes to LRU but still call updateOomAdjLocked() with a specific
         // processes.
@@ -1599,11 +1604,11 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
-        bindService(client, app, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
+        bindService(client, app, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client2, client, null, 0, mock(IBinder.class));
+        bindService(client2, client, null, null, 0, mock(IBinder.class));
         client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2);
@@ -1626,11 +1631,11 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
-        bindService(client2, client, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
+        bindService(client2, client, null, null, 0, mock(IBinder.class));
         client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2);
@@ -1653,18 +1658,18 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
-        bindService(client2, client, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
+        bindService(client2, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        bindService(client3, client, null, 0, mock(IBinder.class));
+        bindService(client3, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
-        bindService(client3, client4, null, 0, mock(IBinder.class));
-        bindService(client4, client3, null, 0, mock(IBinder.class));
+        bindService(client3, client4, null, null, 0, mock(IBinder.class));
+        bindService(client4, client3, null, null, 0, mock(IBinder.class));
         client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3, client4);
@@ -1693,16 +1698,16 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
         client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(client2, app, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, null, 0, mock(IBinder.class));
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         client3.mState.setForcingToImportant(new Object());
-        bindService(app, client3, null, 0, mock(IBinder.class));
+        bindService(app, client3, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3);
 
@@ -1718,17 +1723,17 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
-        bindService(client2, app, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, null, 0, mock(IBinder.class));
         WindowProcessController wpc = client2.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         client3.mState.setForcingToImportant(new Object());
-        bindService(app, client3, null, 0, mock(IBinder.class));
+        bindService(app, client3, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3);
 
@@ -1743,11 +1748,11 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
-        bindService(client2, app, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, null, 0, mock(IBinder.class));
         WindowProcessController wpc = client2.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
@@ -1755,7 +1760,7 @@
         ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
         client4.mState.setForcingToImportant(new Object());
-        bindService(app, client4, null, 0, mock(IBinder.class));
+        bindService(app, client4, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3, client4);
 
@@ -1770,21 +1775,21 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, 0, mock(IBinder.class));
-        bindService(client2, app, null, 0, mock(IBinder.class));
+        bindService(client, client2, null, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, null, 0, mock(IBinder.class));
         WindowProcessController wpc = client2.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         client3.mState.setForcingToImportant(new Object());
-        bindService(app, client3, null, 0, mock(IBinder.class));
+        bindService(app, client3, null, null, 0, mock(IBinder.class));
         ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
         client4.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(app, client4, null, 0, mock(IBinder.class));
+        bindService(app, client4, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3, client4);
 
@@ -1802,15 +1807,15 @@
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         WindowProcessController wpc = client.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(app, client2, null, 0, mock(IBinder.class));
+        bindService(app, client2, null, null, 0, mock(IBinder.class));
         client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         client3.mState.setForcingToImportant(new Object());
-        bindService(app, client3, null, 0, mock(IBinder.class));
+        bindService(app, client3, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(client, client2, client3, app);
 
@@ -1826,7 +1831,7 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindProvider(client, client2, null, null, false);
@@ -1846,12 +1851,12 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(app, client, null, null, 0, mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         bindProvider(client, client2, null, null, false);
         client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(client2, app, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2);
 
@@ -1912,9 +1917,9 @@
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         final ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
-        bindService(app1, client1, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+        bindService(app1, client1, null, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                 mock(IBinder.class));
-        bindService(app2, client2, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+        bindService(app2, client2, null, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                 mock(IBinder.class));
         client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
         client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
@@ -1929,8 +1934,10 @@
         assertBfsl(app1);
         assertBfsl(app2);
 
-        bindService(app1, client1, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
-        bindService(app2, client2, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
+        bindService(app1, client1, null, null, Context.BIND_SCHEDULE_LIKE_TOP_APP,
+                mock(IBinder.class));
+        bindService(app2, client2, null, null, Context.BIND_SCHEDULE_LIKE_TOP_APP,
+                mock(IBinder.class));
         updateOomAdj(client1, client2, app1, app2);
 
         assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1946,8 +1953,8 @@
                 SCHED_GROUP_DEFAULT);
         assertBfsl(app2);
 
-        bindService(client2, app1, null, 0, mock(IBinder.class));
-        bindService(app1, client2, null, 0, mock(IBinder.class));
+        bindService(client2, app1, null, null, 0, mock(IBinder.class));
+        bindService(app1, client2, null, null, 0, mock(IBinder.class));
         client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
         updateOomAdj(app1, client1, client2);
         assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
@@ -1968,9 +1975,9 @@
         client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
         client2.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
 
-        final ServiceRecord s1 = bindService(app1, client1, null,
+        final ServiceRecord s1 = bindService(app1, client1, null, null,
                 Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, mock(IBinder.class));
-        final ServiceRecord s2 = bindService(app2, client2, null,
+        final ServiceRecord s2 = bindService(app2, client2, null, null,
                 Context.BIND_IMPORTANT, mock(IBinder.class));
 
         updateOomAdj(client1, client2, app1, app2);
@@ -1980,7 +1987,7 @@
         assertProcStates(app2, PROCESS_STATE_PERSISTENT, PERSISTENT_SERVICE_ADJ,
                 SCHED_GROUP_DEFAULT);
 
-        bindService(app2, client1, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
+        bindService(app2, client1, null, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
                 mock(IBinder.class));
         updateOomAdj(app2);
         assertProcStates(app2, PROCESS_STATE_PERSISTENT, PERSISTENT_SERVICE_ADJ,
@@ -1995,9 +2002,9 @@
         client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         client2.mState.setHasOverlayUi(true);
 
-        bindService(app1, client1, s1, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
+        bindService(app1, client1, null, s1, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
                 mock(IBinder.class));
-        bindService(app2, client2, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
+        bindService(app2, client2, null, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
                 mock(IBinder.class));
 
         updateOomAdj(client1, client2, app1, app2);
@@ -2030,7 +2037,7 @@
         app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
-        bindService(app1, client1, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
+        bindService(app1, client1, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
 
         updateOomAdj(client1, app1);
 
@@ -2051,7 +2058,8 @@
         app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
 
-        bindService(app1, client1, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+        bindService(app1, client1, null, null, Context.BIND_ALMOST_PERCEPTIBLE,
+                mock(IBinder.class));
 
         updateOomAdj(client1, app1);
 
@@ -2121,19 +2129,19 @@
 
         final ComponentName cn1 = ComponentName.unflattenFromString(
                 MOCKAPP_PACKAGENAME + "/.TestService");
-        final ServiceRecord s1 = bindService(app1, client1, null, 0, mock(IBinder.class));
+        final ServiceRecord s1 = bindService(app1, client1, null, null, 0, mock(IBinder.class));
         setFieldValue(ServiceRecord.class, s1, "name", cn1);
         s1.startRequested = true;
 
         final ComponentName cn2 = ComponentName.unflattenFromString(
                 MOCKAPP2_PACKAGENAME + "/.TestService");
-        final ServiceRecord s2 = bindService(app2, client2, null, 0, mock(IBinder.class));
+        final ServiceRecord s2 = bindService(app2, client2, null, null, 0, mock(IBinder.class));
         setFieldValue(ServiceRecord.class, s2, "name", cn2);
         s2.startRequested = true;
 
         final ComponentName cn3 = ComponentName.unflattenFromString(
                 MOCKAPP5_PACKAGENAME + "/.TestService");
-        final ServiceRecord s3 = bindService(app3, client1, null, 0, mock(IBinder.class));
+        final ServiceRecord s3 = bindService(app3, client1, null, null, 0, mock(IBinder.class));
         setFieldValue(ServiceRecord.class, s3, "name", cn3);
         s3.startRequested = true;
 
@@ -2177,7 +2185,7 @@
             clientUidRecord.setIdle(true);
             doReturn(ActivityManager.APP_START_MODE_DELAYED).when(sService)
                     .getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
-                    anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
+                            anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
             doNothing().when(sService.mServices)
                     .scheduleServiceTimeoutLocked(any(ProcessRecord.class));
             updateOomAdj(client1, client2, app1, app2, app3);
@@ -2188,7 +2196,7 @@
         } finally {
             doCallRealMethod().when(sService)
                     .getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
-                    anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
+                            anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
             sService.mServices.mServiceMap.clear();
             sService.mOomAdjuster.mActiveUids.clear();
         }
@@ -2223,7 +2231,7 @@
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(app, app2, null, 0, mock(IBinder.class));
+        bindService(app, app2, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, app2);
 
@@ -2242,12 +2250,12 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, app2, null, 0, mock(IBinder.class));
+        bindService(app, app2, null, null, 0, mock(IBinder.class));
         ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(app2, app3, null, 0, mock(IBinder.class));
+        bindService(app2, app3, null, null, 0, mock(IBinder.class));
         app3.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(app3, app, null, 0, mock(IBinder.class));
+        bindService(app3, app, null, null, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, app2, app3);
 
@@ -2278,21 +2286,21 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+        ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
         ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(app2, app3, null, 0, mock(IBinder.class));
-        bindService(app3, app, null, 0, mock(IBinder.class));
+        bindService(app2, app3, null, null, 0, mock(IBinder.class));
+        bindService(app3, app, null, null, 0, mock(IBinder.class));
         WindowProcessController wpc = app3.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         app4.mState.setHasOverlayUi(true);
-        bindService(app, app4, s, 0, mock(IBinder.class));
+        bindService(app, app4, null, s, 0, mock(IBinder.class));
         ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
         app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(app, app5, s, 0, mock(IBinder.class));
+        bindService(app, app5, null, s, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, app2, app3, app4, app5);
 
@@ -2320,21 +2328,21 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+        ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
         ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(app2, app3, null, 0, mock(IBinder.class));
-        bindService(app3, app, null, 0, mock(IBinder.class));
+        bindService(app2, app3, null, null, 0, mock(IBinder.class));
+        bindService(app3, app, null, null, 0, mock(IBinder.class));
         WindowProcessController wpc = app3.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         app4.mState.setHasOverlayUi(true);
-        bindService(app, app4, s, 0, mock(IBinder.class));
+        bindService(app, app4, null, s, 0, mock(IBinder.class));
         ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
         app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(app, app5, s, 0, mock(IBinder.class));
+        bindService(app, app5, null, s, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app5, app4, app3, app2, app);
 
@@ -2362,21 +2370,21 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+        ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
         ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(app2, app3, null, 0, mock(IBinder.class));
-        bindService(app3, app, null, 0, mock(IBinder.class));
+        bindService(app2, app3, null, null, 0, mock(IBinder.class));
+        bindService(app3, app, null, null, 0, mock(IBinder.class));
         WindowProcessController wpc = app3.getWindowProcessController();
         doReturn(true).when(wpc).isHomeProcess();
         ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         app4.mState.setHasOverlayUi(true);
-        bindService(app, app4, s, 0, mock(IBinder.class));
+        bindService(app, app4, null, s, 0, mock(IBinder.class));
         ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
                 MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
         app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
-        bindService(app, app5, s, 0, mock(IBinder.class));
+        bindService(app, app5, null, s, 0, mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app3, app4, app2, app, app5);
 
@@ -2404,15 +2412,19 @@
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
         ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
-        bindService(app, client, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+        bindService(app, client, null, null, Context.BIND_INCLUDE_CAPABILITIES,
+                mock(IBinder.class));
         ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
-        bindService(client, client2, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
-        bindService(client2, app, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+        bindService(client, client2, null, null, Context.BIND_INCLUDE_CAPABILITIES,
+                mock(IBinder.class));
+        bindService(client2, app, null, null, Context.BIND_INCLUDE_CAPABILITIES,
+                mock(IBinder.class));
         ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
                 MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
         client3.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
-        bindService(app, client3, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+        bindService(app, client3, null, null, Context.BIND_INCLUDE_CAPABILITIES,
+                mock(IBinder.class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         updateOomAdj(app, client, client2, client3);
 
@@ -2472,10 +2484,10 @@
         ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
                 MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
         long now = SystemClock.uptimeMillis();
-        ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+        ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
         s.startRequested = true;
         s.lastActivity = now;
-        s = bindService(app2, app, null, 0, mock(IBinder.class));
+        s = bindService(app2, app, null, null, 0, mock(IBinder.class));
         s.startRequested = true;
         s.lastActivity = now;
         ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
@@ -2507,11 +2519,11 @@
         final int userOwner = 0;
         final int userOther = 1;
         final int cachedAdj1 = sService.mConstants.USE_TIERED_CACHED_ADJ
-                               ? CACHED_APP_MIN_ADJ + 10
-                               : CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+                ? CACHED_APP_MIN_ADJ + 10
+                : CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
         final int cachedAdj2 = sService.mConstants.USE_TIERED_CACHED_ADJ
-                               ? CACHED_APP_MIN_ADJ + 10
-                               : cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
+                ? CACHED_APP_MIN_ADJ + 10
+                : cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
         doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
 
         final ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
@@ -2626,7 +2638,7 @@
 
         // Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and
         // verify that its OOM adjustment level is unaffected.
-        bindService(app, app, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+        bindService(app, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
         app.mServices.updateHasAboveClientLocked();
         assertFalse(app.mServices.hasAboveClient());
 
@@ -2644,12 +2656,12 @@
         final ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
                 MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
         long now = SystemClock.uptimeMillis();
-        ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+        ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
         s.startRequested = true;
         s.lastActivity = now;
-        s = bindService(app2, app3, null, 0, mock(IBinder.class));
+        s = bindService(app2, app3, null, null, 0, mock(IBinder.class));
         s.lastActivity = now;
-        s = bindService(app3, app2, null, 0, mock(IBinder.class));
+        s = bindService(app3, app2, null, null, 0, mock(IBinder.class));
         s.lastActivity = now;
 
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -2678,7 +2690,7 @@
         // 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));
+        bindService(null, app, null, 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.
@@ -2772,91 +2784,37 @@
                 ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true);
     }
 
-    private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
-            String packageName, boolean hasShownUi) {
-        long now = SystemClock.uptimeMillis();
-        return makeProcessRecord(sService, pid, uid, processName,
-                packageName, 12345, Build.VERSION_CODES.CUR_DEVELOPMENT,
-                now, now, now, 12345, UNKNOWN_ADJ, UNKNOWN_ADJ,
-                UNKNOWN_ADJ, CACHED_APP_MAX_ADJ,
-                SCHED_GROUP_DEFAULT, SCHED_GROUP_DEFAULT,
-                PROCESS_STATE_NONEXISTENT, PROCESS_STATE_NONEXISTENT,
-                PROCESS_STATE_NONEXISTENT, PROCESS_STATE_NONEXISTENT,
-                0, 0, false, false, false, ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE,
-                false, false, false, hasShownUi, false, false, false, false, false, false, null,
-                0, Long.MIN_VALUE, Long.MIN_VALUE, true, 0, null, false);
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_SdkSandbox_attributedClient() {
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        ProcessRecord attributedClient = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, true));
+        ProcessRecord sandboxService = spy(new ProcessRecordBuilder(MOCKAPP_PID,
+                MOCKAPP_SDK_SANDBOX_UID, MOCKAPP_SDK_SANDBOX_PROCESSNAME, MOCKAPP_PACKAGENAME)
+                .setSdkSandboxClientAppPackage(MOCKAPP3_PACKAGENAME)
+                .build());
+
+        setProcessesToLru(sandboxService, client, attributedClient);
+
+        client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+        attributedClient.mServices.setHasForegroundServices(true, 0, true);
+        bindService(sandboxService, client, attributedClient, null, 0, mock(IBinder.class));
+        sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        updateOomAdj();
+        assertProcStates(client, PROCESS_STATE_PERSISTENT, PERSISTENT_PROC_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(attributedClient, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(sandboxService, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
     }
 
-    private ProcessRecord makeProcessRecord(ActivityManagerService service, int pid, int uid,
-            String processName, String packageName, long versionCode, int targetSdkVersion,
-            long lastActivityTime, long lastPssTime, long nextPssTime, long lastPss, int maxAdj,
-            int setRawAdj, int curAdj, int setAdj, int curSchedGroup, int setSchedGroup,
-            int curProcState, int repProcState, int curRawProcState, int setProcState,
-            int connectionGroup, int connectionImportance, boolean serviceb,
-            boolean hasClientActivities, boolean hasForegroundServices, int fgServiceTypes,
-            boolean hasForegroundActivities, boolean repForegroundActivities, boolean systemNoUi,
-            boolean hasShownUi, boolean hasTopUi, boolean hasOverlayUi,
-            boolean runningRemoteAnimation, boolean hasAboveClient, boolean treatLikeActivity,
-            boolean killedByAm, Object forcingToImportant, int numOfCurReceivers,
-            long lastProviderTime, long lastTopTime, boolean cached, int numOfExecutingServices,
-            String isolatedEntryPoint, boolean execServicesFg) {
-        ApplicationInfo ai = spy(new ApplicationInfo());
-        ai.uid = uid;
-        ai.packageName = packageName;
-        ai.longVersionCode = versionCode;
-        ai.targetSdkVersion = targetSdkVersion;
-        ProcessRecord app = new ProcessRecord(service, ai, processName, uid);
-        final ProcessStateRecord state = app.mState;
-        final ProcessServiceRecord services = app.mServices;
-        final ProcessReceiverRecord receivers = app.mReceivers;
-        final ProcessProfileRecord profile = app.mProfile;
-        final ProcessProviderRecord providers = app.mProviders;
-        app.makeActive(mock(IApplicationThread.class), sService.mProcessStats);
-        app.setLastActivityTime(lastActivityTime);
-        app.setKilledByAm(killedByAm);
-        app.setIsolatedEntryPoint(isolatedEntryPoint);
-        setFieldValue(ProcessRecord.class, app, "mWindowProcessController",
-                mock(WindowProcessController.class));
-        profile.setLastPssTime(lastPssTime);
-        profile.setNextPssTime(nextPssTime);
-        profile.setLastPss(lastPss);
-        state.setMaxAdj(maxAdj);
-        state.setSetRawAdj(setRawAdj);
-        state.setCurAdj(curAdj);
-        state.setSetAdj(setAdj);
-        state.setCurrentSchedulingGroup(curSchedGroup);
-        state.setSetSchedGroup(setSchedGroup);
-        state.setCurProcState(curProcState);
-        state.setReportedProcState(repProcState);
-        state.setCurRawProcState(curRawProcState);
-        state.setSetProcState(setProcState);
-        state.setServiceB(serviceb);
-        state.setRepForegroundActivities(repForegroundActivities);
-        state.setHasForegroundActivities(hasForegroundActivities);
-        state.setSystemNoUi(systemNoUi);
-        state.setHasShownUi(hasShownUi);
-        state.setHasTopUi(hasTopUi);
-        state.setRunningRemoteAnimation(runningRemoteAnimation);
-        state.setHasOverlayUi(hasOverlayUi);
-        state.setCached(cached);
-        state.setLastTopTime(lastTopTime);
-        state.setForcingToImportant(forcingToImportant);
-        services.setConnectionGroup(connectionGroup);
-        services.setConnectionImportance(connectionImportance);
-        services.setHasClientActivities(hasClientActivities);
-        services.setHasForegroundServices(hasForegroundServices, fgServiceTypes,
-                /* hasNoneType=*/false);
-        services.setHasAboveClient(hasAboveClient);
-        services.setTreatLikeActivity(treatLikeActivity);
-        services.setExecServicesFg(execServicesFg);
-        for (int i = 0; i < numOfExecutingServices; i++) {
-            services.startExecutingService(mock(ServiceRecord.class));
-        }
-        for (int i = 0; i < numOfCurReceivers; i++) {
-            receivers.addCurReceiver(mock(BroadcastRecord.class));
-        }
-        providers.setLastProviderTime(lastProviderTime);
-        return app;
+    private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
+            String packageName, boolean hasShownUi) {
+        return new ProcessRecordBuilder(pid, uid, processName, packageName).setHasShownUi(
+                hasShownUi).build();
     }
 
     private ServiceRecord makeServiceRecord(ProcessRecord app) {
@@ -2870,6 +2828,7 @@
         record.appInfo = app.info;
         setFieldValue(ServiceRecord.class, record, "bindings", new ArrayMap<>());
         setFieldValue(ServiceRecord.class, record, "pendingStarts", new ArrayList<>());
+        setFieldValue(ServiceRecord.class, record, "isSdkSandbox", app.isSdkSandbox);
         return record;
     }
 
@@ -2892,11 +2851,11 @@
     }
 
     private ServiceRecord bindService(ProcessRecord service, ProcessRecord client,
-            ServiceRecord record, long bindFlags, IBinder binder) {
+            ProcessRecord attributedClient, ServiceRecord record, long bindFlags, IBinder binder) {
         if (record == null) {
             record = makeServiceRecord(service);
         }
-        AppBindRecord binding = new AppBindRecord(record, null, client, null);
+        AppBindRecord binding = new AppBindRecord(record, null, client, attributedClient);
         ConnectionRecord cr = spy(new ConnectionRecord(binding,
                 mock(ActivityServiceConnectionsHolder.class),
                 mock(IServiceConnection.class), bindFlags,
@@ -2961,4 +2920,140 @@
             assertBfsl(app);
         }
     }
+
+    private static class ProcessRecordBuilder {
+        @SuppressWarnings("UnusedVariable")
+        int mPid;
+        int mUid;
+        String mProcessName;
+        String mPackageName;
+        long mVersionCode = 12345;
+        int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+        long mLastActivityTime;
+        long mLastPssTime;
+        long mNextPssTime;
+        long mLastPss = 12345;
+        int mMaxAdj = UNKNOWN_ADJ;
+        int mSetRawAdj = UNKNOWN_ADJ;
+        int mCurAdj = UNKNOWN_ADJ;
+        int mSetAdj = CACHED_APP_MAX_ADJ;
+        int mCurSchedGroup = SCHED_GROUP_DEFAULT;
+        int mSetSchedGroup = SCHED_GROUP_DEFAULT;
+        int mCurProcState = PROCESS_STATE_NONEXISTENT;
+        int mRepProcState = PROCESS_STATE_NONEXISTENT;
+        int mCurRawProcState = PROCESS_STATE_NONEXISTENT;
+        int mSetProcState = PROCESS_STATE_NONEXISTENT;
+        int mConnectionGroup = 0;
+        int mConnectionImportance = 0;
+        boolean mServiceb = false;
+        boolean mHasClientActivities = false;
+        boolean mHasForegroundServices = false;
+        int mFgServiceTypes = ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
+        boolean mHasForegroundActivities = false;
+        boolean mRepForegroundActivities = false;
+        boolean mSystemNoUi = false;
+        boolean mHasShownUi = false;
+        boolean mHasTopUi = false;
+        boolean mHasOverlayUi = false;
+        boolean mRunningRemoteAnimation = false;
+        boolean mHasAboveClient = false;
+        boolean mTreatLikeActivity = false;
+        boolean mKilledByAm = false;
+        Object mForcingToImportant;
+        int mNumOfCurReceivers = 0;
+        long mLastProviderTime = Long.MIN_VALUE;
+        long mLastTopTime = Long.MIN_VALUE;
+        boolean mCached = true;
+        int mNumOfExecutingServices = 0;
+        String mIsolatedEntryPoint = null;
+        boolean mExecServicesFg = false;
+        String mSdkSandboxClientAppPackage = null;
+
+        ProcessRecordBuilder(int pid, int uid, String processName, String packageName) {
+            mPid = pid;
+            mUid = uid;
+            mProcessName = processName;
+            mPackageName = packageName;
+
+            long now = SystemClock.uptimeMillis();
+            mLastActivityTime = now;
+            mLastPssTime = now;
+            mNextPssTime = now;
+        }
+
+        ProcessRecordBuilder setHasShownUi(boolean hasShownUi) {
+            mHasShownUi = hasShownUi;
+            return this;
+        }
+
+        ProcessRecordBuilder setSdkSandboxClientAppPackage(String sdkSandboxClientAppPackage) {
+            mSdkSandboxClientAppPackage = sdkSandboxClientAppPackage;
+            return this;
+        }
+
+        @SuppressWarnings("GuardedBy")
+        public ProcessRecord build() {
+            ApplicationInfo ai = spy(new ApplicationInfo());
+            ai.uid = mUid;
+            ai.packageName = mPackageName;
+            ai.longVersionCode = mVersionCode;
+            ai.targetSdkVersion = mTargetSdkVersion;
+            doCallRealMethod().when(sService).getPackageManagerInternal();
+            doReturn(null).when(sPackageManagerInternal).getApplicationInfo(
+                    eq(mSdkSandboxClientAppPackage), anyLong(), anyInt(), anyInt());
+            ProcessRecord app = new ProcessRecord(sService, ai, mProcessName, mUid,
+                    mSdkSandboxClientAppPackage, -1, null);
+            final ProcessStateRecord state = app.mState;
+            final ProcessServiceRecord services = app.mServices;
+            final ProcessReceiverRecord receivers = app.mReceivers;
+            final ProcessProfileRecord profile = app.mProfile;
+            final ProcessProviderRecord providers = app.mProviders;
+            app.makeActive(mock(IApplicationThread.class), sService.mProcessStats);
+            app.setLastActivityTime(mLastActivityTime);
+            app.setKilledByAm(mKilledByAm);
+            app.setIsolatedEntryPoint(mIsolatedEntryPoint);
+            setFieldValue(ProcessRecord.class, app, "mWindowProcessController",
+                    mock(WindowProcessController.class));
+            profile.setLastPssTime(mLastPssTime);
+            profile.setNextPssTime(mNextPssTime);
+            profile.setLastPss(mLastPss);
+            state.setMaxAdj(mMaxAdj);
+            state.setSetRawAdj(mSetRawAdj);
+            state.setCurAdj(mCurAdj);
+            state.setSetAdj(mSetAdj);
+            state.setCurrentSchedulingGroup(mCurSchedGroup);
+            state.setSetSchedGroup(mSetSchedGroup);
+            state.setCurProcState(mCurProcState);
+            state.setReportedProcState(mRepProcState);
+            state.setCurRawProcState(mCurRawProcState);
+            state.setSetProcState(mSetProcState);
+            state.setServiceB(mServiceb);
+            state.setRepForegroundActivities(mRepForegroundActivities);
+            state.setHasForegroundActivities(mHasForegroundActivities);
+            state.setSystemNoUi(mSystemNoUi);
+            state.setHasShownUi(mHasShownUi);
+            state.setHasTopUi(mHasTopUi);
+            state.setRunningRemoteAnimation(mRunningRemoteAnimation);
+            state.setHasOverlayUi(mHasOverlayUi);
+            state.setCached(mCached);
+            state.setLastTopTime(mLastTopTime);
+            state.setForcingToImportant(mForcingToImportant);
+            services.setConnectionGroup(mConnectionGroup);
+            services.setConnectionImportance(mConnectionImportance);
+            services.setHasClientActivities(mHasClientActivities);
+            services.setHasForegroundServices(mHasForegroundServices, mFgServiceTypes,
+                    /* hasNoneType=*/false);
+            services.setHasAboveClient(mHasAboveClient);
+            services.setTreatLikeActivity(mTreatLikeActivity);
+            services.setExecServicesFg(mExecServicesFg);
+            for (int i = 0; i < mNumOfExecutingServices; i++) {
+                services.startExecutingService(mock(ServiceRecord.class));
+            }
+            for (int i = 0; i < mNumOfCurReceivers; i++) {
+                receivers.addCurReceiver(mock(BroadcastRecord.class));
+            }
+            providers.setLastProviderTime(mLastProviderTime);
+            return app;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java b/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java
new file mode 100644
index 0000000..08a6529
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.adaptiveauth;
+
+import static android.adaptiveauth.Flags.FLAG_ENABLE_ADAPTIVE_AUTH;
+import static android.adaptiveauth.Flags.FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS;
+import static android.security.Flags.FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
+import static com.android.server.adaptiveauth.AdaptiveAuthService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.hardware.biometrics.AuthenticationStateListener;
+import android.hardware.biometrics.BiometricManager;
+import android.os.RemoteException;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
+import com.android.internal.widget.LockSettingsStateListener;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * atest FrameworksServicesTests:AdaptiveAuthServiceTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AdaptiveAuthServiceTest {
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    private static final int PRIMARY_USER_ID = 0;
+    private static final int MANAGED_PROFILE_USER_ID = 12;
+    private static final int DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS = 0;
+    private static final int REASON_UNKNOWN = 0; // BiometricRequestConstants.RequestReason
+
+    private Context mContext;
+    private AdaptiveAuthService mAdaptiveAuthService;
+
+    @Mock
+    LockPatternUtils mLockPatternUtils;
+    @Mock
+    private LockSettingsInternal mLockSettings;
+    @Mock
+    private BiometricManager mBiometricManager;
+    @Mock
+    private KeyguardManager mKeyguardManager;
+    @Mock
+    private WindowManagerInternal mWindowManager;
+    @Mock
+    private UserManagerInternal mUserManager;
+
+    @Captor
+    ArgumentCaptor<LockSettingsStateListener> mLockSettingsStateListenerCaptor;
+    @Captor
+    ArgumentCaptor<AuthenticationStateListener> mAuthenticationStateListenerCaptor;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mSetFlagsRule.enableFlags(FLAG_ENABLE_ADAPTIVE_AUTH);
+        mSetFlagsRule.enableFlags(FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS);
+        mSetFlagsRule.enableFlags(FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS);
+
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
+        when(mContext.getSystemService(KeyguardManager.class)).thenReturn(mKeyguardManager);
+
+        LocalServices.removeServiceForTest(LockSettingsInternal.class);
+        LocalServices.addService(LockSettingsInternal.class, mLockSettings);
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+        LocalServices.addService(WindowManagerInternal.class, mWindowManager);
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        LocalServices.addService(UserManagerInternal.class, mUserManager);
+
+        mAdaptiveAuthService = new AdaptiveAuthService(mContext, mLockPatternUtils);
+        mAdaptiveAuthService.init();
+
+        verify(mLockSettings).registerLockSettingsStateListener(
+                mLockSettingsStateListenerCaptor.capture());
+        verify(mBiometricManager).registerAuthenticationStateListener(
+                mAuthenticationStateListenerCaptor.capture());
+
+        // Set PRIMARY_USER_ID as the parent of MANAGED_PROFILE_USER_ID
+        when(mUserManager.getProfileParentId(eq(MANAGED_PROFILE_USER_ID)))
+                .thenReturn(PRIMARY_USER_ID);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(LockSettingsInternal.class);
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+    }
+
+    @Test
+    public void testReportAuthAttempt_primaryAuthSucceeded()
+            throws RemoteException {
+        mLockSettingsStateListenerCaptor.getValue().onAuthenticationSucceeded(PRIMARY_USER_ID);
+        waitForAuthCompletion();
+
+        verifyNotLockDevice(DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+                PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_primaryAuthFailed_once()
+            throws RemoteException {
+        mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+        waitForAuthCompletion();
+
+        verifyNotLockDevice(1 /* expectedCntFailedAttempts */, PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_primaryAuthFailed_multiple_deviceCurrentlyLocked()
+            throws RemoteException {
+        // Device is currently locked and Keyguard is showing
+        when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(true);
+        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
+
+        for (int i = 0; i < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; i++) {
+            mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+        }
+        waitForAuthCompletion();
+
+        verifyNotLockDevice(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+                PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_primaryAuthFailed_multiple_deviceCurrentlyNotLocked()
+            throws RemoteException {
+        // Device is currently not locked and Keyguard is not showing
+        when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(false);
+        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
+
+        for (int i = 0; i < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; i++) {
+            mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+        }
+        waitForAuthCompletion();
+
+        verifyLockDevice(PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_biometricAuthSucceeded()
+            throws RemoteException {
+        mAuthenticationStateListenerCaptor.getValue()
+                .onAuthenticationSucceeded(REASON_UNKNOWN, PRIMARY_USER_ID);
+        waitForAuthCompletion();
+
+        verifyNotLockDevice(DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+                PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_biometricAuthFailed_once()
+            throws RemoteException {
+        mAuthenticationStateListenerCaptor.getValue()
+                .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+        waitForAuthCompletion();
+
+        verifyNotLockDevice(1 /* expectedCntFailedAttempts */, PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyLocked()
+            throws RemoteException {
+        // Device is currently locked and Keyguard is showing
+        when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(true);
+        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
+
+        for (int i = 0; i < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; i++) {
+            mAuthenticationStateListenerCaptor.getValue()
+                    .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+        }
+        waitForAuthCompletion();
+
+        verifyNotLockDevice(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+                PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyNotLocked()
+            throws RemoteException {
+        // Device is currently not locked and Keyguard is not showing
+        when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(false);
+        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
+
+        for (int i = 0; i < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; i++) {
+            mAuthenticationStateListenerCaptor.getValue()
+                    .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+        }
+        waitForAuthCompletion();
+
+        verifyLockDevice(PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_biometricAuthFailedThenPrimaryAuthSucceeded()
+            throws RemoteException {
+        // Three failed biometric auth attempts
+        for (int i = 0; i < 3; i++) {
+            mAuthenticationStateListenerCaptor.getValue()
+                    .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+        }
+        // One successful primary auth attempt
+        mLockSettingsStateListenerCaptor.getValue().onAuthenticationSucceeded(PRIMARY_USER_ID);
+        waitForAuthCompletion();
+
+        verifyNotLockDevice(DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+                PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_primaryAuthFailedThenBiometricAuthSucceeded()
+            throws RemoteException {
+        // Three failed primary auth attempts
+        for (int i = 0; i < 3; i++) {
+            mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+        }
+        // One successful biometric auth attempt
+        mAuthenticationStateListenerCaptor.getValue()
+                .onAuthenticationSucceeded(REASON_UNKNOWN, PRIMARY_USER_ID);
+        waitForAuthCompletion();
+
+        verifyNotLockDevice(DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+                PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_primaryUser()
+            throws RemoteException {
+        // Three failed primary auth attempts
+        for (int i = 0; i < 3; i++) {
+            mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+        }
+        // Two failed biometric auth attempts
+        for (int i = 0; i < 2; i++) {
+            mAuthenticationStateListenerCaptor.getValue()
+                    .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+        }
+        waitForAuthCompletion();
+
+        verifyLockDevice(PRIMARY_USER_ID);
+    }
+
+    @Test
+    public void testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_profileOfPrimaryUser()
+            throws RemoteException {
+        // Three failed primary auth attempts
+        for (int i = 0; i < 3; i++) {
+            mLockSettingsStateListenerCaptor.getValue()
+                    .onAuthenticationFailed(MANAGED_PROFILE_USER_ID);
+        }
+        // Two failed biometric auth attempts
+        for (int i = 0; i < 2; i++) {
+            mAuthenticationStateListenerCaptor.getValue()
+                    .onAuthenticationFailed(REASON_UNKNOWN, MANAGED_PROFILE_USER_ID);
+        }
+        waitForAuthCompletion();
+
+        verifyLockDevice(MANAGED_PROFILE_USER_ID);
+    }
+
+    private void verifyNotLockDevice(int expectedCntFailedAttempts, int userId) {
+        assertEquals(expectedCntFailedAttempts,
+                mAdaptiveAuthService.mFailedAttemptsForUser.get(userId));
+        verify(mWindowManager, never()).lockNow();
+    }
+
+    private void verifyLockDevice(int userId) {
+        assertEquals(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS,
+                mAdaptiveAuthService.mFailedAttemptsForUser.get(userId));
+        verify(mLockPatternUtils).requireStrongAuth(
+                eq(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST), eq(userId));
+        // If userId is MANAGED_PROFILE_USER_ID, the StrongAuthFlag of its parent (PRIMARY_USER_ID)
+        // should also be verified
+        if (userId == MANAGED_PROFILE_USER_ID) {
+            verify(mLockPatternUtils).requireStrongAuth(
+                    eq(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST), eq(PRIMARY_USER_ID));
+        }
+        verify(mWindowManager).lockNow();
+    }
+
+    /**
+     * Wait for all auth events to complete before verification
+     */
+    private static void waitForAuthCompletion() {
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/adaptiveauth/OWNERS b/services/tests/servicestests/src/com/android/server/adaptiveauth/OWNERS
new file mode 100644
index 0000000..0218a78
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/adaptiveauth/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/adaptiveauth/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index aefa6de..abd3abe 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -75,12 +75,12 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.internal.util.test.LocalServiceKeeperRule;
+import com.android.server.LocalServices;
 import com.android.server.testutils.OffsettableClock;
 import com.android.server.wm.WindowManagerInternal;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -164,17 +164,15 @@
     @Captor
     private ArgumentCaptor<ContentRecordingSession> mSessionCaptor;
 
-    @Rule
-    public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule();
-
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
         when(mWatcherCallback.asBinder()).thenReturn(new Binder());
 
-        mLocalServiceKeeperRule.overrideLocalService(ActivityManagerInternal.class, mAmInternal);
-        mLocalServiceKeeperRule.overrideLocalService(WindowManagerInternal.class,
-                mWindowManagerInternal);
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.addService(ActivityManagerInternal.class, mAmInternal);
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+        LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
 
         mContext = spy(new ContextWrapper(
                 InstrumentationRegistry.getInstrumentation().getTargetContext()));
@@ -189,6 +187,12 @@
         mService = new MediaProjectionManagerService(mContext);
     }
 
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+    }
+
     @Test
     public void testGetActiveProjectionInfoInternal() throws NameNotFoundException {
         assertThat(mService.getActiveProjectionInfo()).isNull();
@@ -384,16 +388,16 @@
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
                 service);
         // No starts yet, and not timed out yet - so still valid.
-        assertThat(projection.isValidInternal()).isTrue();
+        assertThat(projection.isValid()).isTrue();
 
         // Only one start - so still valid.
         projection.start(mIMediaProjectionCallback);
-        assertThat(projection.isValidInternal()).isTrue();
+        assertThat(projection.isValid()).isTrue();
 
         // Second start - technically allowed to start again, without stopping in between.
         // Token should no longer be valid.
         projection.start(mIMediaProjectionCallback);
-        assertThat(projection.isValidInternal()).isFalse();
+        assertThat(projection.isValid()).isFalse();
     }
 
     @Test
@@ -403,17 +407,17 @@
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
                 service);
         // No starts yet, and not timed out yet - so still valid.
-        assertThat(projection.isValidInternal()).isTrue();
+        assertThat(projection.isValid()).isTrue();
 
         // Only one start - so still valid.
         projection.start(mIMediaProjectionCallback);
-        assertThat(projection.isValidInternal()).isTrue();
+        assertThat(projection.isValid()).isTrue();
 
         projection.stop();
 
         // Second start - so not valid.
         projection.start(mIMediaProjectionCallback);
-        assertThat(projection.isValidInternal()).isFalse();
+        assertThat(projection.isValid()).isFalse();
     }
 
     @Test
@@ -438,7 +442,7 @@
         mClock.fastForward(projection.mDefaultTimeoutMs + 10);
 
         // Immediate timeout - so no longer valid.
-        assertThat(projection.isValidInternal()).isFalse();
+        assertThat(projection.isValid()).isFalse();
     }
 
     @Test
@@ -448,10 +452,10 @@
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
                 service);
         // Simulate MediaProjection#createVirtualDisplay being invoked previously.
-        projection.notifyVirtualDisplayCreatedInternal(10);
+        projection.notifyVirtualDisplayCreated(10);
 
         // Trying to re-use token on another MediaProjection#createVirtualDisplay - no longer valid.
-        assertThat(projection.isValidInternal()).isFalse();
+        assertThat(projection.isValid()).isFalse();
     }
 
     // TODO(269273190): Test flag using compat annotations instead.
@@ -467,7 +471,7 @@
         // Second start - so not valid.
         projection.start(mIMediaProjectionCallback);
 
-        assertThrows(SecurityException.class, projection::isValidInternal);
+        assertThrows(SecurityException.class, projection::isValid);
     }
 
     // TODO(269273190): Test flag using compat annotations instead.
@@ -484,7 +488,7 @@
         // Second start - so not valid.
         projection.start(mIMediaProjectionCallback);
 
-        assertThat(projection.isValidInternal()).isFalse();
+        assertThat(projection.isValid()).isFalse();
     }
 
     @Test
@@ -623,7 +627,7 @@
         mService.setUserReviewGrantedConsentResult(RECORD_CONTENT_DISPLAY, projection);
 
         // Virtual Display is finally created.
-        projection.notifyVirtualDisplayCreatedInternal(10);
+        projection.notifyVirtualDisplayCreated(10);
         verifySetSessionWithContent(ContentRecordingSession.RECORD_CONTENT_DISPLAY);
     }
 
@@ -726,7 +730,7 @@
             throws Exception {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
         projection.start(mIMediaProjectionCallback);
-        projection.notifyVirtualDisplayCreatedInternal(10);
+        projection.notifyVirtualDisplayCreated(10);
         // Waiting for user to review consent.
         assertThat(mService.isCurrentProjection(projection)).isTrue();
         doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
@@ -781,9 +785,9 @@
             @RecordContent int recordedContent)
             throws NameNotFoundException {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
-        projection.setLaunchCookieInternal(new LaunchCookie());
+        projection.setLaunchCookie(new LaunchCookie());
         projection.start(mIMediaProjectionCallback);
-        projection.notifyVirtualDisplayCreatedInternal(10);
+        projection.notifyVirtualDisplayCreated(10);
         // Waiting for user to review consent.
         doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
                 any(ContentRecordingSession.class));
@@ -804,7 +808,7 @@
             throws NameNotFoundException {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
         projection.start(mIMediaProjectionCallback);
-        projection.notifyVirtualDisplayCreatedInternal(10);
+        projection.notifyVirtualDisplayCreated(10);
         // Waiting for user to review consent.
         doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
                 eq(mWaitingDisplaySession));
@@ -822,7 +826,7 @@
     public void testSetUserReviewGrantedConsentResult_displayMirroring_noPriorSession()
             throws NameNotFoundException {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
-        projection.setLaunchCookieInternal(new LaunchCookie());
+        projection.setLaunchCookie(new LaunchCookie());
         projection.start(mIMediaProjectionCallback);
         // Skip setting the prior session details.
 
@@ -841,7 +845,7 @@
     public void testSetUserReviewGrantedConsentResult_displayMirroring_sessionNotWaiting()
             throws NameNotFoundException {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
-        projection.setLaunchCookieInternal(new LaunchCookie());
+        projection.setLaunchCookie(new LaunchCookie());
         projection.start(mIMediaProjectionCallback);
         // Session is not waiting for user's consent.
         doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 4451cae..5f2abc3 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.NETWORK_STACK;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
@@ -58,9 +59,11 @@
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_TOP;
 import static android.net.NetworkPolicyManager.BACKGROUND_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
+import static android.net.NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+import static android.net.NetworkPolicyManager.TOP_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.allowedReasonsToString;
 import static android.net.NetworkPolicyManager.blockedReasonsToString;
 import static android.net.NetworkPolicyManager.uidPoliciesToString;
@@ -88,6 +91,7 @@
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
+import static com.android.server.net.NetworkPolicyManagerService.UID_MSG_STATE_CHANGED;
 import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons;
 import static com.android.server.net.NetworkPolicyManagerService.normalizeTemplate;
 
@@ -196,8 +200,6 @@
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.usage.AppStandbyInternal;
 
-import com.google.common.util.concurrent.AbstractFuture;
-
 import libcore.io.Streams;
 
 import org.junit.After;
@@ -241,10 +243,8 @@
 import java.util.Set;
 import java.util.TimeZone;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -2247,6 +2247,123 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
+    public void testUidObserverFiltersProcStateChanges() throws Exception {
+        int testProcStateSeq = 0;
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // First callback for uid.
+            callOnUidStatechanged(UID_A, BACKGROUND_THRESHOLD_STATE + 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Doesn't cross the background threshold.
+            callOnUidStatechanged(UID_A, BACKGROUND_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Crosses the background threshold.
+            callOnUidStatechanged(UID_A, BACKGROUND_THRESHOLD_STATE - 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Doesn't cross the foreground threshold.
+            callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE + 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Crosses the foreground threshold.
+            callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Doesn't cross the top threshold.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE + 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Crosses the top threshold.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Doesn't cross any other threshold.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE - 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
+    public void testUidObserverFiltersStaleChanges() throws Exception {
+        final int testProcStateSeq = 51;
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // First callback for uid.
+            callOnUidStatechanged(UID_B, BACKGROUND_THRESHOLD_STATE + 100, testProcStateSeq,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Stale callback because the procStateSeq is smaller.
+            callOnUidStatechanged(UID_B, BACKGROUND_THRESHOLD_STATE - 100, testProcStateSeq - 10,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
+    public void testUidObserverFiltersCapabilityChanges() throws Exception {
+        int testProcStateSeq = 0;
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // First callback for uid.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // The same process-state with one network capability added.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // The same process-state with another network capability added.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
+                            | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // The same process-state with all capabilities, but no change in network capabilities.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_ALL);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+    }
+
+    @Test
     public void testLowPowerStandbyAllowlist() throws Exception {
         // Chain background is also enabled but these procstates are important enough to be exempt.
         callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 0);
@@ -2559,17 +2676,6 @@
         verify(mStatsManager).setDefaultGlobalAlert(anyLong());
     }
 
-    private static class TestAbstractFuture<T> extends AbstractFuture<T> {
-        @Override
-        public T get() throws InterruptedException, ExecutionException {
-            try {
-                return get(5, TimeUnit.SECONDS);
-            } catch (TimeoutException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
     private static void assertTimeEquals(long expected, long actual) {
         if (expected != actual) {
             fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 847c9d0..d5eeaa7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1561,7 +1561,7 @@
                 .build();
 
         final int result = starter.recycleTask(task, null, null, null,
-                BalVerdict.ALLOW_BY_DEFAULT);
+                BalVerdict.ALLOW_PRIVILEGED);
         assertThat(result == START_SUCCESS).isTrue();
         assertThat(starter.mAddingToTask).isTrue();
     }
@@ -2075,7 +2075,7 @@
         starter.startActivityInner(target, source, null /* voiceSession */,
                 null /* voiceInteractor */, 0 /* startFlags */,
                 options, inTask, inTaskFragment,
-                BalVerdict.ALLOW_BY_DEFAULT,
+                BalVerdict.ALLOW_PRIVILEGED,
                 null /* intentGrants */, -1 /* realCallingUid */);
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 60dfe6f..887e5ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -811,7 +811,7 @@
 
     @Test
     public void testDisplayContentUpdatesRecording_withSurface() {
-        createContentRecorder(createDefaultDisplayInfo());
+        defaultInit();
         // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
         // mirror.
         setUpDefaultTaskDisplayAreaWindowToken();
@@ -820,7 +820,6 @@
         // getDisplaySurfaceDefaultSize (done by surfaceControlMirrors in setUp).
         final DisplayContent virtualDisplay =
                 mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId());
-        virtualDisplay.setContentRecorder(mContentRecorder);
         mWm.mContentRecordingController.setContentRecordingSessionLocked(mDisplaySession, mWm);
         virtualDisplay.updateRecording();
 
@@ -845,7 +844,6 @@
         // WHEN getting the DisplayContent for the new virtual display.
         final DisplayContent virtualDisplay =
                 mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId());
-        virtualDisplay.setContentRecorder(mContentRecorder);
         // Return the default display as the value to mirror to ensure the VD with flag mirroring
         // creates a ContentRecordingSession automatically.
         doReturn(DEFAULT_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
index 42004c3..c84fe08 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
@@ -24,7 +24,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 
 import android.platform.test.annotations.Presubmit;
@@ -32,8 +31,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.ContentRecorder.MediaProjectionManagerWrapper;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -71,11 +68,6 @@
         mVirtualDisplayId = mVirtualDisplayContent.getDisplayId();
         mWm.mRoot.onDisplayAdded(mVirtualDisplayId);
         spyOn(mVirtualDisplayContent);
-        final MediaProjectionManagerWrapper
-                mediaProjectionManagerWrapper = mock(MediaProjectionManagerWrapper.class);
-        final ContentRecorder contentRecorder = new ContentRecorder(mVirtualDisplayContent,
-                mediaProjectionManagerWrapper, /* correctForAnisotropicPixels= */ false);
-        mVirtualDisplayContent.setContentRecorder(contentRecorder);
 
         mDefaultSession.setVirtualDisplayId(mVirtualDisplayId);
         mWaitingDisplaySession.setVirtualDisplayId(mVirtualDisplayId);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index c404c77..bb5887d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -187,7 +187,7 @@
                 /* options */null,
                 /* inTask */null,
                 /* inTaskFragment */ null,
-                BalVerdict.ALLOW_BY_DEFAULT,
+                BalVerdict.ALLOW_PRIVILEGED,
                 /* intentGrants */null,
                 /* realCaiingUid */ -1);
 
@@ -217,7 +217,7 @@
                 /* options= */null,
                 /* inTask= */null,
                 /* inTaskFragment= */ null,
-                BalVerdict.ALLOW_BY_DEFAULT,
+                BalVerdict.ALLOW_PRIVILEGED,
                 /* intentGrants= */null,
                 /* realCaiingUid */ -1);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 8b0fc2c..cd3ce91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -1424,6 +1424,25 @@
         assertFalse(window2.isSecureLocked());
     }
 
+    @Test
+    @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
+    public void testIsSecureLocked_sensitiveContentBlockOrClearScreenCaptureForApp() {
+        String testPackage = "test";
+        int ownerId = 20;
+        final WindowState window = createWindow(null, TYPE_APPLICATION, "window", ownerId);
+        window.mAttrs.packageName = testPackage;
+        assertFalse(window.isSecureLocked());
+
+        PackageInfo blockedPackage = new PackageInfo(testPackage, ownerId);
+        ArraySet<PackageInfo> blockedPackages = new ArraySet();
+        blockedPackages.add(blockedPackage);
+        mWm.mSensitiveContentPackages.addBlockScreenCaptureForApps(blockedPackages);
+        assertTrue(window.isSecureLocked());
+
+        mWm.mSensitiveContentPackages.removeBlockScreenCaptureForApps(blockedPackages);
+        assertFalse(window.isSecureLocked());
+    }
+
     private static class TestImeTargetChangeListener implements ImeTargetChangeListener {
         private IBinder mImeTargetToken;
         private boolean mIsRemoved;
diff --git a/telecomm/java/android/telecom/CallAttributes.java b/telecomm/java/android/telecom/CallAttributes.java
index 8c6e101..afd34fc 100644
--- a/telecomm/java/android/telecom/CallAttributes.java
+++ b/telecomm/java/android/telecom/CallAttributes.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -24,6 +25,8 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.server.telecom.flags.Flags;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
@@ -113,7 +116,8 @@
     public static final int VIDEO_CALL = 2;
 
     /** @hide */
-    @IntDef(value = {SUPPORTS_SET_INACTIVE, SUPPORTS_STREAM, SUPPORTS_TRANSFER}, flag = true)
+    @IntDef(value = {SUPPORTS_SET_INACTIVE, SUPPORTS_STREAM, SUPPORTS_TRANSFER,
+            SUPPORTS_VIDEO_CALLING}, flag = true)
     @Retention(RetentionPolicy.SOURCE)
     public @interface CallCapability {
     }
@@ -133,6 +137,12 @@
      * The call can be completely transferred from one endpoint to another.
      */
     public static final int SUPPORTS_TRANSFER = 1 << 3;
+    /**
+     * The call supports video calling. This allows clients to gate video calling on a per call
+     * basis as opposed to re-registering the phone account.
+     */
+    @FlaggedApi(Flags.FLAG_TRANSACTIONAL_VIDEO_STATE)
+    public static final int SUPPORTS_VIDEO_CALLING = 1 << 4;
 
     /**
      * Build an instance of {@link CallAttributes}. In order to build a valid instance, a
diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java
index a1407869..808a575 100644
--- a/telecomm/java/android/telecom/CallControl.java
+++ b/telecomm/java/android/telecom/CallControl.java
@@ -293,12 +293,50 @@
         try {
             mServerInterface.setMuteState(isMuted,
                     new CallControlResultReceiver("requestMuteState", executor, callback));
-
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
+     /**
+     * Request a new video state for the ongoing call. This can only be changed if the application
+     * has registered a {@link PhoneAccount} with the
+     * {@link PhoneAccount#CAPABILITY_SUPPORTS_VIDEO_CALLING} and set the
+     * {@link CallAttributes#SUPPORTS_VIDEO_CALLING} when adding the call via
+     * {@link TelecomManager#addCall(CallAttributes, Executor, OutcomeReceiver,
+     *                                                      CallControlCallback, CallEventCallback)}
+     *
+     * @param videoState to report to Telecom. To see the valid argument to pass,
+      *                   see {@link CallAttributes.CallType}.
+     * @param executor   The {@link Executor} on which the {@link OutcomeReceiver} callback
+     *                   will be called on.
+     * @param callback   that will be completed on the Telecom side that details success or failure
+     *                   of the requested operation.
+     *
+     *                   {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
+     *                   switched the video state.
+     *
+     *                   {@link OutcomeReceiver#onError} will be called if Telecom has failed to set
+     *                   the new video state.  A {@link CallException} will be passed
+     *                   that details why the operation failed.
+     * @throws IllegalArgumentException if the argument passed for videoState is invalid.  To see a
+     * list of valid states, see {@link CallAttributes.CallType}.
+     */
+     @FlaggedApi(Flags.FLAG_TRANSACTIONAL_VIDEO_STATE)
+     public void requestVideoState(@CallAttributes.CallType int videoState,
+             @CallbackExecutor @NonNull Executor executor,
+             @NonNull OutcomeReceiver<Void, CallException> callback) {
+         validateVideoState(videoState);
+         Objects.requireNonNull(executor);
+         Objects.requireNonNull(callback);
+         try {
+             mServerInterface.requestVideoState(videoState, mCallId,
+                     new CallControlResultReceiver("requestVideoState", executor, callback));
+         } catch (RemoteException e) {
+             throw e.rethrowAsRuntimeException();
+         }
+     }
+
     /**
      * Raises an event to the {@link android.telecom.InCallService} implementations tracking this
      * call via {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)}.
diff --git a/telecomm/java/android/telecom/CallEventCallback.java b/telecomm/java/android/telecom/CallEventCallback.java
index a41c011..b0438bf 100644
--- a/telecomm/java/android/telecom/CallEventCallback.java
+++ b/telecomm/java/android/telecom/CallEventCallback.java
@@ -16,9 +16,12 @@
 
 package android.telecom;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.os.Bundle;
 
+import com.android.server.telecom.flags.Flags;
+
 import java.util.List;
 
 /**
@@ -51,6 +54,14 @@
     void onMuteStateChanged(boolean isMuted);
 
     /**
+     * Called when the video state changes.
+     *
+     * @param videoState The current video state.
+     */
+    @FlaggedApi(Flags.FLAG_TRANSACTIONAL_VIDEO_STATE)
+    default void onVideoStateChanged(@CallAttributes.CallType int videoState) {}
+
+    /**
      * Telecom is informing the client user requested call streaming but the stream can't be
      * started.
      *
diff --git a/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java b/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
index 467e89c..a2c6086 100644
--- a/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
+++ b/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
@@ -33,6 +33,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.server.telecom.flags.Flags;
+
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
@@ -148,6 +150,7 @@
         private static final String ON_REQ_ENDPOINT_CHANGE = "onRequestEndpointChange";
         private static final String ON_AVAILABLE_CALL_ENDPOINTS = "onAvailableCallEndpointsChanged";
         private static final String ON_MUTE_STATE_CHANGED = "onMuteStateChanged";
+        private static final String ON_VIDEO_STATE_CHANGED = "onVideoStateChanged";
         private static final String ON_CALL_STREAMING_FAILED = "onCallStreamingFailed";
         private static final String ON_EVENT = "onEvent";
 
@@ -261,6 +264,11 @@
             handleEventCallback(callId, ON_MUTE_STATE_CHANGED, isMuted);
         }
 
+        @Override
+        public void onVideoStateChanged(String callId, int videoState) {
+            handleEventCallback(callId, ON_VIDEO_STATE_CHANGED, videoState);
+        }
+
         public void handleEventCallback(String callId, String action, Object arg) {
             Log.d(TAG, TextUtils.formatSimple("hEC: [%s], callId=[%s]", action, callId));
             // lookup the callEventCallback associated with the particular call
@@ -281,6 +289,11 @@
                             case ON_MUTE_STATE_CHANGED:
                                 callback.onMuteStateChanged((boolean) arg);
                                 break;
+                            case ON_VIDEO_STATE_CHANGED:
+                                if (Flags.transactionalVideoState()) {
+                                    callback.onVideoStateChanged((int) arg);
+                                }
+                                break;
                             case ON_CALL_STREAMING_FAILED:
                                 callback.onCallStreamingFailed((int) arg /* reason */);
                                 break;
diff --git a/telecomm/java/com/android/internal/telecom/ICallControl.aidl b/telecomm/java/com/android/internal/telecom/ICallControl.aidl
index 372e4a12..ac49660 100644
--- a/telecomm/java/com/android/internal/telecom/ICallControl.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallControl.aidl
@@ -34,4 +34,5 @@
     void requestCallEndpointChange(in CallEndpoint callEndpoint, in ResultReceiver callback);
     void setMuteState(boolean isMuted, in ResultReceiver callback);
     void sendEvent(String callId, String event, in Bundle extras);
+    void requestVideoState(int videoState, String callId, in ResultReceiver callback);
 }
\ No newline at end of file
diff --git a/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl b/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
index 213cafb..e4d6b0c 100644
--- a/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
@@ -45,6 +45,8 @@
     void onCallEndpointChanged(String callId, in CallEndpoint endpoint);
     void onAvailableCallEndpointsChanged(String callId, in List<CallEndpoint> endpoint);
     void onMuteStateChanged(String callId, boolean isMuted);
+    // -- Video Related
+    void onVideoStateChanged(String callId, int videoState);
     // -- Events
     void onEvent(String callId, String event, in Bundle extras);
     // hidden methods that help with cleanup
diff --git a/telephony/java/android/telephony/DomainSelectionService.java b/telephony/java/android/telephony/DomainSelectionService.java
index 4ff9712..633694a 100644
--- a/telephony/java/android/telephony/DomainSelectionService.java
+++ b/telephony/java/android/telephony/DomainSelectionService.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
@@ -855,7 +856,8 @@
      *
      * @return an {@link Executor} used to execute methods called remotely by the framework.
      */
-    public @NonNull Executor onCreateExecutor() {
+    @SuppressLint("OnNameExpected")
+    public @NonNull Executor getCreateExecutor() {
         return Runnable::run;
     }
 
@@ -869,7 +871,7 @@
     public final @NonNull Executor getCachedExecutor() {
         synchronized (mExecutorLock) {
             if (mExecutor == null) {
-                Executor e = onCreateExecutor();
+                Executor e = getCreateExecutor();
                 mExecutor = (e != null) ? e : Runnable::run;
             }
             return mExecutor;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 041822b..fd9aae9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -15011,6 +15011,27 @@
     }
 
     /**
+     * Get the emergency assistance package name.
+     *
+     * @return the package name of the emergency assistance app.
+     * @throws IllegalStateException if emergency assistance is not enabled.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @FlaggedApi(android.permission.flags.Flags.FLAG_GET_EMERGENCY_ROLE_HOLDER_API_ENABLED)
+    @NonNull
+    @SystemApi
+    public String getEmergencyAssistancePackage() {
+        if (!isEmergencyAssistanceEnabled()) {
+            throw new IllegalStateException("isEmergencyAssistanceEnabled() is false.");
+        }
+        String emergencyRole = mContext.getSystemService(RoleManager.class)
+                .getEmergencyRoleHolder(mContext.getUserId());
+        return Objects.requireNonNull(emergencyRole, "Emergency role holder must not be null");
+    }
+
+    /**
      * Get the emergency number list based on current locale, sim, default, modem and network.
      *
      * <p>In each returned list, the emergency number {@link EmergencyNumber} coming from higher
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
deleted file mode 100755
index a6847ae..0000000
--- a/tools/hoststubgen/scripts/run-all-tests.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-# 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.
-
-source "${0%/*}"/../common.sh
-
-# Move to the top directory of hoststubgen
-cd ..
-
-ATEST_ARGS="--host"
-
-# These tests are known to pass.
-READY_TEST_MODULES=(
-  hoststubgen-test-tiny-test
-  CtsUtilTestCasesRavenwood
-  CtsOsTestCasesRavenwood # This one uses native sustitution, so let's run it too.
-)
-
-MUST_BUILD_MODULES=(
-    "${NOT_READY_TEST_MODULES[*]}"
-)
-
-# First, build all the test / etc modules. This shouldn't fail.
-run m "${MUST_BUILD_MODULES[@]}"
-
-# Run the hoststubgen unittests / etc
-run atest $ATEST_ARGS hoststubgentest hoststubgen-invoke-test
-
-# Next, run the golden check. This should always pass too.
-# The following scripts _should_ pass too, but they depend on the internal paths to soong generated
-# files, and they may fail when something changes in the build system.
-run ./hoststubgen/test-tiny-framework/diff-and-update-golden.sh
-
-run ./hoststubgen/test-tiny-framework/run-test-manually.sh
-run atest $ATEST_ARGS tiny-framework-dump-test
-
-# This script is already broken on goog/master
-# run ./scripts/build-framework-hostside-jars-without-genrules.sh
-
-# These tests should all pass.
-run atest $ATEST_ARGS ${READY_TEST_MODULES[*]}
-
-echo ""${0##*/}" finished, with no failures. Ready to submit!"