Merge "Fix location ignore settings bugs"
diff --git a/Android.bp b/Android.bp
index e19ca84..9b62b7a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,8 +49,6 @@
         "rs/java/**/*.java",
 
         ":framework-javastream-protos",
-        // TODO: Resolve circular library dependency and remove media1-srcs
-        ":media1-srcs",
 
         "core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl",
         "core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl",
@@ -505,7 +503,11 @@
         "media/java/android/media/session/ICallback.aidl",
         "media/java/android/media/session/IOnMediaKeyListener.aidl",
         "media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl",
+        "media/java/android/media/session/ISession.aidl",
         "media/java/android/media/session/ISession2TokensListener.aidl",
+        "media/java/android/media/session/ISessionCallback.aidl",
+        "media/java/android/media/session/ISessionController.aidl",
+        "media/java/android/media/session/ISessionControllerCallback.aidl",
         "media/java/android/media/session/ISessionManager.aidl",
         "media/java/android/media/soundtrigger/ISoundTriggerDetectionService.aidl",
         "media/java/android/media/soundtrigger/ISoundTriggerDetectionServiceClient.aidl",
@@ -520,6 +522,8 @@
         "media/java/android/media/tv/ITvInputSessionCallback.aidl",
         "media/java/android/media/tv/ITvRemoteProvider.aidl",
         "media/java/android/media/tv/ITvRemoteServiceInput.aidl",
+        "media/java/android/service/media/IMediaBrowserService.aidl",
+        "media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl",
         "telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl",
         "telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl",
         "telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl",
diff --git a/api/current.txt b/api/current.txt
index 6b88547..4a1fccf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11233,6 +11233,7 @@
 
   public class LauncherApps {
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(String, android.os.UserHandle);
+    method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllPackageInstallerSessions();
     method @Nullable public android.content.pm.LauncherApps.AppUsageLimit getAppUsageLimit(String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
@@ -11249,13 +11250,16 @@
     method public void pinShortcuts(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
+    method public void registerPackageInstallerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.content.pm.PackageInstaller.SessionCallback);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public boolean shouldHideFromSuggestions(@NonNull String, @NonNull android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public void startPackageInstallerSessionDetailsActivity(android.content.pm.PackageInstaller.SessionInfo, android.graphics.Rect, android.os.Bundle);
     method public void startShortcut(@NonNull String, @NonNull String, @Nullable android.graphics.Rect, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
     method public void startShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
+    method public void unregisterPackageInstallerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
     field public static final String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
     field public static final String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
     field public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
@@ -11445,6 +11449,7 @@
     method public long getSize();
     method public int getStagedSessionErrorCode();
     method public String getStagedSessionErrorMessage();
+    method public android.os.UserHandle getUser();
     method public boolean isActive();
     method public boolean isMultiPackage();
     method public boolean isSealed();
@@ -25582,6 +25587,14 @@
     field public static final int PLAYER_STATE_PAUSED = 1003; // 0x3eb
     field public static final int PLAYER_STATE_PLAYING = 1004; // 0x3ec
     field public static final int PLAYER_STATE_PREPARED = 1002; // 0x3ea
+    field public static final int PREPARE_DRM_STATUS_KEY_EXCHANGE_ERROR = 7; // 0x7
+    field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3
+    field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1
+    field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2
+    field public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5; // 0x5
+    field public static final int PREPARE_DRM_STATUS_RESTORE_ERROR = 6; // 0x6
+    field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0
+    field public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4; // 0x4
     field public static final int SEEK_CLOSEST = 3; // 0x3
     field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
     field public static final int SEEK_NEXT_SYNC = 1; // 0x1
@@ -38497,13 +38510,13 @@
     field public static final String BUCKET_ID = "bucket_id";
     field public static final String DATE_TAKEN = "datetaken";
     field public static final String DESCRIPTION = "description";
+    field public static final String GROUP_ID = "group_id";
     field public static final String IS_PRIVATE = "isprivate";
     field @Deprecated public static final String LATITUDE = "latitude";
     field @Deprecated public static final String LONGITUDE = "longitude";
     field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
     field public static final String ORIENTATION = "orientation";
     field @Deprecated public static final String PICASA_ID = "picasa_id";
-    field public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
   }
 
   public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns {
@@ -38557,6 +38570,8 @@
     field public static final String IS_TRASHED = "is_trashed";
     field public static final String MIME_TYPE = "mime_type";
     field public static final String OWNER_PACKAGE_NAME = "owner_package_name";
+    field public static final String PRIMARY_DIRECTORY = "primary_directory";
+    field public static final String SECONDARY_DIRECTORY = "secondary_directory";
     field public static final String SIZE = "_size";
     field public static final String TITLE = "title";
     field public static final String WIDTH = "width";
@@ -38624,13 +38639,13 @@
     field public static final String DATE_TAKEN = "datetaken";
     field public static final String DESCRIPTION = "description";
     field public static final String DURATION = "duration";
+    field public static final String GROUP_ID = "group_id";
     field public static final String IS_PRIVATE = "isprivate";
     field public static final String LANGUAGE = "language";
     field @Deprecated public static final String LATITUDE = "latitude";
     field @Deprecated public static final String LONGITUDE = "longitude";
     field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
     field public static final String RESOLUTION = "resolution";
-    field public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
     field public static final String TAGS = "tags";
   }
 
@@ -38854,6 +38869,7 @@
     field @Deprecated public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
     field @Deprecated public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
     field @Deprecated public static final int LOCATION_MODE_OFF = 0; // 0x0
+    field @Deprecated public static final int LOCATION_MODE_ON = 3; // 0x3
     field @Deprecated public static final int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
     field @Deprecated public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
     field @Deprecated public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
@@ -41878,10 +41894,6 @@
     method public void showSession(android.os.Bundle, int);
     field public static final String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final String SERVICE_META_DATA = "android.voice_interaction";
-    field public static final int VOICE_STATE_CONDITIONAL_LISTENING = 1; // 0x1
-    field public static final int VOICE_STATE_FULFILLING = 3; // 0x3
-    field public static final int VOICE_STATE_LISTENING = 2; // 0x2
-    field public static final int VOICE_STATE_NONE = 0; // 0x0
   }
 
   public class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
diff --git a/api/system-current.txt b/api/system-current.txt
index d061d01..d67974b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3675,7 +3675,7 @@
   }
 
   public final class MediaSessionEngine implements java.lang.AutoCloseable {
-    ctor public MediaSessionEngine(@NonNull android.content.Context, @NonNull android.media.session.SessionLink, @NonNull android.media.session.SessionCallbackLink, @NonNull android.media.session.MediaSessionEngine.CallbackStub);
+    ctor public MediaSessionEngine(@NonNull android.content.Context, @NonNull android.media.session.SessionLink, @NonNull android.media.session.SessionCallbackLink);
     method public void close();
     method public String getCallingPackage();
     method @NonNull public android.media.session.MediaController getController();
@@ -3700,33 +3700,6 @@
     method public void setSessionActivity(@Nullable android.app.PendingIntent);
   }
 
-  public static final class MediaSessionEngine.CallbackStub {
-    ctor public MediaSessionEngine.CallbackStub();
-    method public void onAdjustVolume(String, int, int, android.media.session.ControllerCallbackLink, int);
-    method public void onCommand(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle, android.os.ResultReceiver);
-    method public void onCustomAction(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
-    method public void onFastForward(String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onMediaButton(String, int, int, android.content.Intent, int, android.os.ResultReceiver);
-    method public void onMediaButtonFromController(String, int, int, android.media.session.ControllerCallbackLink, android.content.Intent);
-    method public void onNext(String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onPause(String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onPlay(String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onPlayFromMediaId(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
-    method public void onPlayFromSearch(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
-    method public void onPlayFromUri(String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
-    method public void onPrepare(String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onPrepareFromMediaId(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
-    method public void onPrepareFromSearch(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
-    method public void onPrepareFromUri(String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
-    method public void onPrevious(String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onRate(String, int, int, android.media.session.ControllerCallbackLink, android.media.Rating);
-    method public void onRewind(String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onSeekTo(String, int, int, android.media.session.ControllerCallbackLink, long);
-    method public void onSetVolumeTo(String, int, int, android.media.session.ControllerCallbackLink, int);
-    method public void onSkipToTrack(String, int, int, android.media.session.ControllerCallbackLink, long);
-    method public void onStop(String, int, int, android.media.session.ControllerCallbackLink);
-  }
-
   public static interface MediaSessionEngine.MediaButtonEventDelegate {
     method public boolean onMediaButtonIntent(android.content.Intent);
   }
@@ -5844,6 +5817,7 @@
   public static interface DeviceConfig.ActivityManager {
     field public static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
     field public static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
+    field public static final String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate";
     field public static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
     field public static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
     field public static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
@@ -5859,9 +5833,9 @@
   }
 
   public static interface DeviceConfig.AttentionManagerService {
+    field public static final String COMPONENT_NAME = "component_name";
     field public static final String NAMESPACE = "attention_manager_service";
-    field public static final String PROPERTY_COMPONENT_NAME = "component_name";
-    field public static final String PROPERTY_SERVICE_ENABLED = "service_enabled";
+    field public static final String SERVICE_ENABLED = "service_enabled";
   }
 
   public static interface DeviceConfig.ContentCapture {
@@ -5875,9 +5849,9 @@
   }
 
   public static interface DeviceConfig.IntelligenceAttention {
+    field public static final String ATTENTION_ENABLED = "attention_enabled";
+    field public static final String ATTENTION_SETTINGS = "attention_settings";
     field public static final String NAMESPACE = "intelligence_attention";
-    field public static final String PROPERTY_ATTENTION_ENABLED = "attention_enabled";
-    field public static final String PROPERTY_ATTENTION_SETTINGS = "attention_settings";
   }
 
   public static interface DeviceConfig.NotificationAssistant {
@@ -5892,8 +5866,8 @@
 
   public static interface DeviceConfig.Privacy {
     field public static final String NAMESPACE = "privacy";
-    field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "enable_location_access_check";
-    field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "enable_permissions_hub";
+    field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled";
+    field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
   }
 
   public static interface DeviceConfig.RuntimeNative {
@@ -5907,8 +5881,9 @@
 
   public static interface DeviceConfig.Telephony {
     field public static final String NAMESPACE = "telephony";
-    field public static final String PROPERTY_ENABLE_RAMPING_RINGER = "enable_ramping_ringer";
-    field public static final String PROPERTY_RAMPING_RINGER_DURATION = "ramping_duration";
+    field public static final String RAMPING_RINGER_DURATION = "ramping_ringer_duration";
+    field public static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
+    field public static final String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration";
   }
 
   public final class DocumentsContract {
diff --git a/api/test-current.txt b/api/test-current.txt
index db547ed..2f4d455 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1744,7 +1744,7 @@
 
   public static interface DeviceConfig.Privacy {
     field public static final String NAMESPACE = "privacy";
-    field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "enable_location_access_check";
+    field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled";
   }
 
   public final class MediaStore {
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index d1bc377..50bb3c7 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -24,6 +24,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IOnAppsChangedListener;
 import android.content.pm.LauncherApps;
+import android.content.pm.IPackageInstallerCallback;
+import android.content.pm.PackageInstaller;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
@@ -44,6 +46,9 @@
             String callingPackage, String packageName, in UserHandle user);
     ActivityInfo resolveActivity(
             String callingPackage, in ComponentName component, in UserHandle user);
+    void startSessionDetailsActivityAsUser(in IApplicationThread caller, String callingPackage,
+                in PackageInstaller.SessionInfo sessionInfo, in Rect sourceBounds, in Bundle opts,
+                in UserHandle user);
     void startActivityAsUser(in IApplicationThread caller, String callingPackage,
             in ComponentName component, in Rect sourceBounds,
             in Bundle opts, in UserHandle user);
@@ -79,4 +84,9 @@
             String callingPackage, String packageName, in UserHandle user);
     IntentSender getShortcutConfigActivityIntent(String callingPackage, in ComponentName component,
             in UserHandle user);
+
+    // Unregister is performed using package installer
+    void registerPackageInstallerCallback(String callingPackage,
+            in IPackageInstallerCallback callback);
+    ParceledListSlice getAllSessions(String callingPackage);
 }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 98dd9b3..b0d16cd 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -32,6 +33,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.PackageInstaller.SessionCallback;
+import android.content.pm.PackageInstaller.SessionCallbackDelegate;
+import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
@@ -65,7 +69,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * Class for retrieving a list of launchable activities for the current user and any associated
@@ -154,8 +160,8 @@
     private final PackageManager mPm;
     private final UserManager mUserManager;
 
-    private List<CallbackMessageHandler> mCallbacks
-            = new ArrayList<CallbackMessageHandler>();
+    private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
+    private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
 
     /**
      * Callbacks for package changes to this and related managed profiles.
@@ -572,6 +578,24 @@
     }
 
     /**
+     * Starts an activity to show the details of the specified session.
+     *
+     * @param sessionInfo The SessionInfo of the session
+     * @param sourceBounds The Rect containing the source bounds of the clicked icon
+     * @param opts Options to pass to startActivity
+     */
+    public void startPackageInstallerSessionDetailsActivity(SessionInfo sessionInfo,
+            Rect sourceBounds, Bundle opts) {
+        try {
+            mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
+                    mContext.getPackageName(), sessionInfo, sourceBounds, opts,
+                    sessionInfo.getUser());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Starts the settings activity to show the application details for a
      * package in the specified profile.
      *
@@ -1131,7 +1155,7 @@
     }
 
     /**
-     * Registers a callback for changes to packages in current and managed profiles.
+     * Registers a callback for changes to packages in this user and managed profiles.
      *
      * @param callback The callback to register.
      */
@@ -1140,7 +1164,7 @@
     }
 
     /**
-     * Registers a callback for changes to packages in current and managed profiles.
+     * Registers a callback for changes to packages in this user and managed profiles.
      *
      * @param callback The callback to register.
      * @param handler that should be used to post callbacks on, may be null.
@@ -1446,6 +1470,64 @@
     }
 
     /**
+     * Register a callback to watch for session lifecycle events in this user and managed profiles.
+     * @param callback The callback to register.
+     * @param executor {@link Executor} to handle the callbacks, cannot be null.
+     *
+     * @see PackageInstaller#registerSessionCallback(SessionCallback)
+     */
+    public void registerPackageInstallerSessionCallback(
+            @NonNull @CallbackExecutor Executor executor, @NonNull SessionCallback callback) {
+        if (executor == null) {
+            throw new NullPointerException("Executor must not be null");
+        }
+
+        synchronized (mDelegates) {
+            final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
+                    executor);
+            try {
+                mService.registerPackageInstallerCallback(mContext.getPackageName(),
+                        delegate);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            mDelegates.add(delegate);
+        }
+    }
+
+    /**
+     * Unregisters a callback that was previously registered.
+     *
+     * @param callback The callback to unregister.
+     * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
+     */
+    public void unregisterPackageInstallerSessionCallback(SessionCallback callback) {
+        synchronized (mDelegates) {
+            for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
+                final SessionCallbackDelegate delegate = i.next();
+                if (delegate.mCallback == callback) {
+                    mPm.getPackageInstaller().unregisterSessionCallback(delegate.mCallback);
+                    i.remove();
+                }
+            }
+        }
+    }
+
+    /**
+     * Return list of all known install sessions in this user and managed profiles, regardless
+     * of the installer.
+     *
+     * @see PackageInstaller#getAllSessions()
+     */
+    public @NonNull List<SessionInfo> getAllPackageInstallerSessions() {
+        try {
+            return mService.getAllSessions(mContext.getPackageName()).getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * A helper method to extract a {@link PinItemRequest} set to
      * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
      */
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 2dc014c..4f674bd 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -36,20 +36,21 @@
 import android.os.Build;
 import android.os.FileBridge;
 import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
+import android.os.HandlerExecutor;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.os.ParcelableException;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.ExceptionUtils;
 
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -61,6 +62,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * Offers the ability to install, upgrade, and remove applications on the
@@ -659,8 +661,7 @@
     }
 
     /** {@hide} */
-    private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements
-            Handler.Callback {
+    static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub {
         private static final int MSG_SESSION_CREATED = 1;
         private static final int MSG_SESSION_BADGING_CHANGED = 2;
         private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
@@ -668,63 +669,41 @@
         private static final int MSG_SESSION_FINISHED = 5;
 
         final SessionCallback mCallback;
-        final Handler mHandler;
+        final Executor mExecutor;
 
-        public SessionCallbackDelegate(SessionCallback callback, Looper looper) {
+        SessionCallbackDelegate(SessionCallback callback, Executor executor) {
             mCallback = callback;
-            mHandler = new Handler(looper, this);
-        }
-
-        @Override
-        public boolean handleMessage(Message msg) {
-            final int sessionId = msg.arg1;
-            switch (msg.what) {
-                case MSG_SESSION_CREATED:
-                    mCallback.onCreated(sessionId);
-                    return true;
-                case MSG_SESSION_BADGING_CHANGED:
-                    mCallback.onBadgingChanged(sessionId);
-                    return true;
-                case MSG_SESSION_ACTIVE_CHANGED:
-                    final boolean active = msg.arg2 != 0;
-                    mCallback.onActiveChanged(sessionId, active);
-                    return true;
-                case MSG_SESSION_PROGRESS_CHANGED:
-                    mCallback.onProgressChanged(sessionId, (float) msg.obj);
-                    return true;
-                case MSG_SESSION_FINISHED:
-                    mCallback.onFinished(sessionId, msg.arg2 != 0);
-                    return true;
-            }
-            return false;
+            mExecutor = executor;
         }
 
         @Override
         public void onSessionCreated(int sessionId) {
-            mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget();
+            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onCreated, mCallback,
+                    sessionId).recycleOnUse());
         }
 
         @Override
         public void onSessionBadgingChanged(int sessionId) {
-            mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget();
+            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onBadgingChanged,
+                    mCallback, sessionId).recycleOnUse());
         }
 
         @Override
         public void onSessionActiveChanged(int sessionId, boolean active) {
-            mHandler.obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, active ? 1 : 0)
-                    .sendToTarget();
+            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onActiveChanged,
+                    mCallback, sessionId, active).recycleOnUse());
         }
 
         @Override
         public void onSessionProgressChanged(int sessionId, float progress) {
-            mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress)
-                    .sendToTarget();
+            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onProgressChanged,
+                    mCallback, sessionId, progress).recycleOnUse());
         }
 
         @Override
         public void onSessionFinished(int sessionId, boolean success) {
-            mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0)
-                    .sendToTarget();
+            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onFinished,
+                    mCallback, sessionId, success).recycleOnUse());
         }
     }
 
@@ -758,7 +737,7 @@
     public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
         synchronized (mDelegates) {
             final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
-                    handler.getLooper());
+                    new HandlerExecutor(handler));
             try {
                 mInstaller.registerCallback(delegate, mUserId);
             } catch (RemoteException e) {
@@ -1649,6 +1628,8 @@
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int sessionId;
         /** {@hide} */
+        public int userId;
+        /** {@hide} */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String installerPackageName;
         /** {@hide} */
@@ -1720,6 +1701,7 @@
         /** {@hide} */
         public SessionInfo(Parcel source) {
             sessionId = source.readInt();
+            userId = source.readInt();
             installerPackageName = source.readString();
             resolvedBaseCodePath = source.readString();
             progress = source.readFloat();
@@ -1761,6 +1743,13 @@
         }
 
         /**
+         * Return the user associated with this session.
+         */
+        public UserHandle getUser() {
+            return new UserHandle(userId);
+        }
+
+        /**
          * Return the package name of the app that owns this session.
          */
         public @Nullable String getInstallerPackageName() {
@@ -2091,6 +2080,7 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(sessionId);
+            dest.writeInt(userId);
             dest.writeString(installerPackageName);
             dest.writeString(resolvedBaseCodePath);
             dest.writeFloat(progress);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ef8ca9e..869cf64 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1033,34 +1033,6 @@
         }
     }
 
-    /**
-     * Configures an always-on VPN connection through a specific application.
-     * This connection is automatically granted and persisted after a reboot.
-     *
-     * <p>The designated package should declare a {@link VpnService} in its
-     *    manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
-     *    otherwise the call will fail.
-     *
-     * @param userId The identifier of the user to set an always-on VPN for.
-     * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
-     *                   to remove an existing always-on VPN configuration.
-     * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
-     *        {@code false} otherwise.
-     * @return {@code true} if the package is set as always-on VPN controller;
-     *         {@code false} otherwise.
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
-    public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
-            boolean lockdownEnabled) {
-        try {
-            return mService.setAlwaysOnVpnPackage(
-                    userId, vpnPackage, lockdownEnabled, /* whitelist */ null);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
    /**
      * Returns the package name of the currently set always-on VPN application.
      * If there is no always-on VPN set, or the VPN is provided by the system instead
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
new file mode 100644
index 0000000..b568f15
--- /dev/null
+++ b/core/java/android/os/OWNERS
@@ -0,0 +1,2 @@
+# Zygote
+per-file ZygoteProcess.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 30c0731..92650e1 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -181,10 +181,10 @@
         String NAMESPACE = "intelligence_attention";
 
         /** If {@code true}, enables the attention features. */
-        String PROPERTY_ATTENTION_ENABLED = "attention_enabled";
+        String ATTENTION_ENABLED = "attention_enabled";
 
         /** Settings for the attention features. */
-        String PROPERTY_ATTENTION_SETTINGS = "attention_settings";
+        String ATTENTION_SETTINGS = "attention_settings";
     }
 
     /**
@@ -203,12 +203,12 @@
          * @hide
          */
         @SystemApi
-        String PROPERTY_PERMISSIONS_HUB_ENABLED = "enable_permissions_hub";
+        String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
 
         /**
          * Whether to show location access check notifications.
          */
-        String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "enable_location_access_check";
+        String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled";
     }
 
     /**
@@ -220,13 +220,17 @@
     public interface Telephony {
         String NAMESPACE = "telephony";
         /**
-         * Whether to apply ramping ringer on incoming phone calls.
-         */
-        String PROPERTY_ENABLE_RAMPING_RINGER = "enable_ramping_ringer";
-        /**
          * Ringer ramping time in milliseconds.
          */
-        String PROPERTY_RAMPING_RINGER_DURATION = "ramping_duration";
+        String RAMPING_RINGER_DURATION = "ramping_ringer_duration";
+        /**
+         * Whether to apply ramping ringer on incoming phone calls.
+         */
+        String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
+        /**
+         * Vibration time in milliseconds before ramping ringer starts.
+         */
+        String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration";
     }
 
     /**
@@ -261,6 +265,7 @@
         String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
         String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
         String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
+        String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate";
 
         /**
          * Maximum number of cached processes. See
@@ -279,10 +284,10 @@
         String NAMESPACE = "attention_manager_service";
 
         /** If {@code true}, enables {@link AttentionManagerService} features. */
-        String PROPERTY_SERVICE_ENABLED = "service_enabled";
+        String SERVICE_ENABLED = "service_enabled";
 
         /** Allows a CTS to inject a fake implementation. */
-        String PROPERTY_COMPONENT_NAME = "component_name";
+        String COMPONENT_NAME = "component_name";
     }
 
     /**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 124c50a..0743c23 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -641,6 +641,8 @@
          * location. For example, when this value is left undefined, pending
          * {@link MediaStore.Audio.Media} items are stored under
          * {@link Environment#DIRECTORY_MUSIC}.
+         *
+         * @see MediaColumns#PRIMARY_DIRECTORY
          */
         public void setPrimaryDirectory(@Nullable String primaryDirectory) {
             this.primaryDirectory = primaryDirectory;
@@ -652,6 +654,8 @@
          * <p>
          * You may leave this value undefined to store the media as a direct
          * descendant of the {@link #setPrimaryDirectory(String)} location.
+         *
+         * @see MediaColumns#SECONDARY_DIRECTORY
          */
         public void setSecondaryDirectory(@Nullable String secondaryDirectory) {
             this.secondaryDirectory = secondaryDirectory;
@@ -980,6 +984,26 @@
          * Type: TEXT
          */
         public static final String OWNER_PACKAGE_NAME = "owner_package_name";
+
+        /**
+         * The primary directory name this media exists under. The value may be
+         * {@code NULL} if the media doesn't have a primary directory name.
+         * <p>
+         * Type: TEXT
+         *
+         * @see PendingParams#setPrimaryDirectory(String)
+         */
+        public static final String PRIMARY_DIRECTORY = "primary_directory";
+
+        /**
+         * The secondary directory name this media exists under. The value may
+         * be {@code NULL} if the media doesn't have a secondary directory name.
+         * <p>
+         * Type: TEXT
+         *
+         * @see PendingParams#setSecondaryDirectory(String)
+         */
+        public static final String SECONDARY_DIRECTORY = "secondary_directory";
     }
 
     /**
@@ -1428,13 +1452,20 @@
             public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
 
             /**
-             * The secondary bucket ID of this media item. This can be useful to
-             * present the user a second-level clustering of related media
-             * items. This is a read-only column that is automatically computed.
+             * The group ID of this media item. This can be useful to present
+             * the user a grouping of related media items, such a burst of
+             * images, or a {@code JPG} and {@code DNG} version of the same
+             * image.
+             * <p>
+             * This is a read-only column that is automatically computed based
+             * on the first portion of the filename. For example,
+             * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG}
+             * will have the same {@link #GROUP_ID} because the first portion of
+             * their filenames is identical.
              * <p>
              * Type: INTEGER
              */
-            public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
+            public static final String GROUP_ID = "group_id";
         }
 
         public static final class Media implements ImageColumns {
@@ -2697,13 +2728,20 @@
             public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
 
             /**
-             * The secondary bucket ID of this media item. This can be useful to
-             * present the user a second-level clustering of related media
-             * items. This is a read-only column that is automatically computed.
+             * The group ID of this media item. This can be useful to present
+             * the user a grouping of related media items, such a burst of
+             * images, or a {@code JPG} and {@code DNG} version of the same
+             * image.
+             * <p>
+             * This is a read-only column that is automatically computed based
+             * on the first portion of the filename. For example,
+             * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG}
+             * will have the same {@link #GROUP_ID} because the first portion of
+             * their filenames is identical.
              * <p>
              * Type: INTEGER
              */
-            public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
+            public static final String GROUP_ID = "group_id";
 
             /**
              * The bookmark for the video. Time in ms. Represents the location in the video that the
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ea00698..afa2110 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5874,30 +5874,24 @@
                 "unknown_sources_default_reversed";
 
         /**
-         * Comma-separated list of location providers that activities may access. Do not rely on
-         * this value being present in settings.db or on ContentObserver notifications on the
+         * Comma-separated list of location providers that are accessible. Do not rely on
+         * this value being present or correct, or on ContentObserver notifications on the
          * corresponding Uri.
          *
-         * @deprecated Providers should not be controlled individually. See {@link #LOCATION_MODE}
-          * documentation for information on reading/writing location information.
+         * @deprecated The preferred methods for checking provider status and listening for changes
+         * are via {@link LocationManager#isProviderEnabled(String)} and
+         * {@link LocationManager#PROVIDERS_CHANGED_ACTION}.
          */
         @Deprecated
         public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
 
         /**
-         * The degree of location access enabled by the user.
-         * <p>
-         * When used with {@link #putInt(ContentResolver, String, int)}, must be one of {@link
-         * #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY}, {@link
-         * #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}. When used with {@link
-         * #getInt(ContentResolver, String)}, the caller must gracefully handle additional location
-         * modes that might be added in the future.
-         * <p>
-         * Note: do not rely on this value being present in settings.db or on ContentObserver
-         * notifications for the corresponding Uri. Use {@link LocationManager#MODE_CHANGED_ACTION}
-         * to receive changes in this value.
+         * The current location mode of the device. Do not rely on this value being present or on
+         * ContentObserver notifications on the corresponding Uri.
          *
-         * @deprecated To check location mode, use {@link LocationManager#isLocationEnabled()}.
+         * @deprecated The preferred methods for checking location mode and listening for changes
+         * are via {@link LocationManager#isLocationEnabled()} and
+         * {@link LocationManager#MODE_CHANGED_ACTION}.
          */
         @Deprecated
         public static final String LOCATION_MODE = "location_mode";
@@ -5924,7 +5918,7 @@
         public static final int LOCATION_CHANGER_QUICK_SETTINGS = 2;
 
         /**
-         * Location access disabled.
+         * Location mode is off.
          *
          * @deprecated See {@link #LOCATION_MODE}.
          */
@@ -5932,32 +5926,39 @@
         public static final int LOCATION_MODE_OFF = 0;
 
         /**
-         * Network Location Provider disabled, but GPS and other sensors enabled.
+         * This mode no longer has any distinct meaning, but is interpreted as the location mode is
+         * on.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated See {@link #LOCATION_MODE_ON}.
          */
         @Deprecated
         public static final int LOCATION_MODE_SENSORS_ONLY = 1;
 
         /**
-         * Reduced power usage, such as limiting the number of GPS updates per hour. Requests
-         * with {@link android.location.Criteria#POWER_HIGH} may be downgraded to
-         * {@link android.location.Criteria#POWER_MEDIUM}.
+         * This mode no longer has any distinct meaning, but is interpreted as the location mode is
+         * on.
          *
-         * @deprecated See {@link #LOCATION_MODE}.
+         * @deprecated See {@link #LOCATION_MODE_ON}.
          */
         @Deprecated
         public static final int LOCATION_MODE_BATTERY_SAVING = 2;
 
         /**
-         * Best-effort location computation allowed.
+         * This mode no longer has any distinct meaning, but is interpreted as the location mode is
+         * on.
+         *
+         * @deprecated See {@link #LOCATION_MODE_ON}.
+         */
+        @Deprecated
+        public static final int LOCATION_MODE_HIGH_ACCURACY = 3;
+
+        /**
+         * Location mode is on.
          *
          * @deprecated See {@link #LOCATION_MODE}.
          */
         @Deprecated
-        public static final int LOCATION_MODE_HIGH_ACCURACY = 3;
+        public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY;
 
         /**
          * A flag containing settings used for biometric weak
diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java
index f6e448dc..24d74ff 100644
--- a/core/java/android/service/attention/AttentionService.java
+++ b/core/java/android/service/attention/AttentionService.java
@@ -64,10 +64,10 @@
     /** Attention is present. */
     public static final int ATTENTION_SUCCESS_PRESENT = 1;
 
-    /** Preempted by other camera user. */
+    /** Preempted by other client. */
     public static final int ATTENTION_FAILURE_PREEMPTED = 2;
 
-    /** Preempted by other camera user. */
+    /** Request timed out. */
     public static final int ATTENTION_FAILURE_TIMED_OUT = 3;
 
     /** Unknown reasons for failing to determine the attention. */
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 2789651..e76e096 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -16,7 +16,6 @@
 
 package android.service.voice;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -41,8 +40,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
@@ -80,33 +77,6 @@
      */
     public static final String SERVICE_META_DATA = "android.voice_interaction";
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"VOICE_STATE_"}, value = {
-            VOICE_STATE_NONE,
-            VOICE_STATE_CONDITIONAL_LISTENING,
-            VOICE_STATE_LISTENING,
-            VOICE_STATE_FULFILLING})
-    public @interface VoiceState {
-    }
-
-    /**
-     * Voice assistant inactive.
-     */
-    public static final int VOICE_STATE_NONE = 0;
-    /**
-     * Voice assistant listening, but will only trigger if it hears a request it can fulfill.
-     */
-    public static final int VOICE_STATE_CONDITIONAL_LISTENING = 1;
-    /**
-     * Voice assistant is listening to user speech.
-     */
-    public static final int VOICE_STATE_LISTENING = 2;
-    /**
-     * Voice assistant is fulfilling an action requested by the user.
-     */
-    public static final int VOICE_STATE_FULFILLING = 3;
-
     IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
         @Override
         public void ready() {
@@ -376,7 +346,7 @@
      *
      * @param state value indicating whether the assistant is listening, fulfilling, etc.
      */
-    public final void setVoiceState(@VoiceState int state) {
+    public final void setVoiceState(int state) {
         try {
             mSystemService.setVoiceState(state);
         } catch (RemoteException e) {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index db9351b..2e8b7f0 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -57,6 +57,7 @@
         DEFAULT_FLAGS.put("settings_wifi_dpp", "true");
         DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true");
         DEFAULT_FLAGS.put("settings_wifi_sharing", "true");
+        DEFAULT_FLAGS.put("settings_mainline_module", "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
         DEFAULT_FLAGS.put(SAFETY_HUB, "false");
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
new file mode 100644
index 0000000..602455c
--- /dev/null
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import android.annotation.Nullable;
+import android.app.RemoteAction;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+
+/**
+ * Utility class for inserting and retrieving data in TextClassifier request/response extras.
+ * @hide
+ */
+public final class ExtrasUtils {
+
+    private static final String ACTIONS_INTENTS = "actions-intents";
+    private static final String FOREIGN_LANGUAGE = "foreign-language";
+    private static final String ENTITY_TYPE = "entity-type";
+    private static final String SCORE = "score";
+    private static final String MODEL_VERSION = "model-version";
+    private static final String MODEL_NAME = "model-name";
+
+    private ExtrasUtils() {}
+
+    /**
+     * Bundles and returns foreign language detection information for TextClassifier responses.
+     */
+    static Bundle createForeignLanguageExtra(
+            String language, float score, int modelVersion) {
+        final Bundle bundle = new Bundle();
+        bundle.putString(ENTITY_TYPE, language);
+        bundle.putFloat(SCORE, score);
+        bundle.putInt(MODEL_VERSION, modelVersion);
+        bundle.putString(MODEL_NAME, "langId_v" + modelVersion);
+        return bundle;
+    }
+
+    /**
+     * Stores {@code extra} as foreign language information in TextClassifier response object's
+     * extras {@code container}.
+     */
+    static void putForeignLanguageExtra(Bundle container, Bundle extra) {
+        container.putParcelable(FOREIGN_LANGUAGE, extra);
+    }
+
+    /**
+     * Returns foreign language detection information contained in the TextClassification object.
+     * responses.
+     */
+    @Nullable
+    public static Bundle getForeignLanguageExtra(TextClassification classification) {
+        return classification.getExtras().getBundle(FOREIGN_LANGUAGE);
+    }
+
+    /**
+     * Stores {@code actionIntents} information in TextClassifier response object's extras
+     * {@code container}.
+     */
+    static void putActionsIntents(Bundle container, ArrayList<Intent> actionsIntents) {
+        container.putParcelableArrayList(ACTIONS_INTENTS, actionsIntents);
+    }
+
+    /**
+     * Returns {@code actionIntents} information contained in the TextClassification object.
+     */
+    @Nullable
+    public static ArrayList<Intent> getActionsIntents(TextClassification classification) {
+        return classification.getExtras().getParcelableArrayList(ACTIONS_INTENTS);
+    }
+
+    /**
+     * Returns the first "translate" action found in the {@code classification} object.
+     */
+    @Nullable
+    public static RemoteAction findTranslateAction(TextClassification classification) {
+        final ArrayList<Intent> actionIntents = getActionsIntents(classification);
+        if (actionIntents != null) {
+            final int size = actionIntents.size();
+            for (int i = 0; i < size; i++) {
+                if (Intent.ACTION_TRANSLATE.equals(actionIntents.get(i).getAction())) {
+                    return classification.getActions().get(i);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the entity type contained in the {@code extra}.
+     */
+    @Nullable
+    public static String getEntityType(Bundle extra) {
+        return extra.getString(ENTITY_TYPE);
+    }
+
+    /**
+     * Returns the score contained in the {@code extra}.
+     */
+    @Nullable
+    public static float getScore(Bundle extra) {
+        return extra.getFloat(SCORE, -1);
+    }
+
+    /**
+     * Returns the model name contained in the {@code extra}.
+     */
+    @Nullable
+    public static String getModelName(Bundle extra) {
+        return extra.getString(MODEL_NAME);
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index d9f7965..a059209 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -378,6 +378,8 @@
         @Nullable private OnClickListener mLegacyOnClickListener;
         @Nullable private String mId;
         @Nullable private Bundle mExtras;
+        @NonNull private final ArrayList<Intent> mActionIntents = new ArrayList<>();
+        @Nullable private Bundle mForeignLanguageExtra;
 
         /**
          * Sets the classified text.
@@ -412,8 +414,19 @@
          */
         @NonNull
         public Builder addAction(@NonNull RemoteAction action) {
+            return addAction(action, null);
+        }
+
+        /**
+         * @param intent the intent in the remote action.
+         * @see #addAction(RemoteAction)
+         * @hide
+         */
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+        public Builder addAction(RemoteAction action, @Nullable Intent intent) {
             Preconditions.checkArgument(action != null);
             mActions.add(action);
+            mActionIntents.add(intent);
             return this;
         }
 
@@ -499,13 +512,33 @@
         }
 
         /**
+         * @see #setExtras(Bundle)
+         * @hide
+         */
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+        public Builder setForeignLanguageExtra(@Nullable Bundle extra) {
+            mForeignLanguageExtra = extra;
+            return this;
+        }
+
+        /**
          * Builds and returns a {@link TextClassification} object.
          */
         @NonNull
         public TextClassification build() {
             return new TextClassification(mText, mLegacyIcon, mLegacyLabel, mLegacyIntent,
-                    mLegacyOnClickListener, mActions, mEntityConfidence, mId,
-                    mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+                    mLegacyOnClickListener, mActions, mEntityConfidence, mId, buildExtras());
+        }
+
+        private Bundle buildExtras() {
+            final Bundle extras = mExtras == null ? new Bundle() : mExtras.deepCopy();
+            if (!mActionIntents.isEmpty()) {
+                ExtrasUtils.putActionsIntents(extras, mActionIntents);
+            }
+            if (mForeignLanguageExtra != null) {
+                ExtrasUtils.putForeignLanguageExtra(extras, mForeignLanguageExtra);
+            }
+            return extras.isEmpty() ? Bundle.EMPTY : extras;
         }
     }
 
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
index 45668c0..ba1287f 100644
--- a/core/java/android/view/textclassifier/TextClassificationSession.java
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -71,10 +71,23 @@
 
     @Override
     public void onSelectionEvent(SelectionEvent event) {
-        checkDestroyed();
-        Preconditions.checkNotNull(event);
-        if (mEventHelper.sanitizeEvent(event)) {
-            mDelegate.onSelectionEvent(event);
+        try {
+            if (mEventHelper.sanitizeEvent(event)) {
+                mDelegate.onSelectionEvent(event);
+            }
+        } catch (Exception e) {
+            // Avoid crashing for event reporting.
+            Log.e(LOG_TAG, "Error reporting text classifier selection event", e);
+        }
+    }
+
+    @Override
+    public void onTextClassifierEvent(TextClassifierEvent event) {
+        try {
+            mDelegate.onTextClassifierEvent(event);
+        } catch (Exception e) {
+            // Avoid crashing for event reporting.
+            Log.e(LOG_TAG, "Error reporting text classifier event", e);
         }
     }
 
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 8a688d8..e010155 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -161,7 +161,12 @@
      * No-op TextClassifier.
      * This may be used to turn off TextClassifier features.
      */
-    TextClassifier NO_OP = new TextClassifier() {};
+    TextClassifier NO_OP = new TextClassifier() {
+        @Override
+        public String toString() {
+            return "TextClassifier.NO_OP";
+        }
+    };
 
     /**
      * Extra that is included on activity intents coming from a TextClassifier when
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index cd13cc0..0d4338b 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -141,6 +141,8 @@
     @Nullable private final String mLanguage;
     private final float mScore;
 
+    @Nullable private final String mModelName;
+
     private TextClassifierEvent(
             int eventCategory,
             int eventType,
@@ -156,7 +158,8 @@
             int relativeSuggestedWordEndIndex,
             int[] actionIndex,
             String language,
-            float score) {
+            float score,
+            String modelVersion) {
         mEventCategory = eventCategory;
         mEventType = eventType;
         mEntityTypes = entityTypes;
@@ -172,6 +175,7 @@
         mActionIndices = actionIndex;
         mLanguage = language;
         mScore = score;
+        mModelName = modelVersion;
     }
 
     @Override
@@ -196,6 +200,7 @@
         dest.writeIntArray(mActionIndices);
         dest.writeString(mLanguage);
         dest.writeFloat(mScore);
+        dest.writeString(mModelName);
     }
 
     private static TextClassifierEvent readFromParcel(Parcel in) {
@@ -214,7 +219,8 @@
                 /* relativeSuggestedWordEndIndex= */ in.readInt(),
                 /* actionIndices= */ in.createIntArray(),
                 /* language= */ in.readString(),
-                /* score= */ in.readFloat());
+                /* score= */ in.readFloat(),
+                /* modelVersion= */ in.readString());
     }
 
     /**
@@ -264,6 +270,7 @@
         return mEventIndex;
     }
 
+    // TODO: Remove this API.
     /**
      * Returns the time this event occurred. This is the number of milliseconds since
      * January 1, 1970, 00:00:00 GMT. 0 indicates not set.
@@ -339,6 +346,15 @@
     }
 
     /**
+     * Returns the model name.
+     * @hide
+     */
+    @Nullable
+    public String getModelName() {
+        return mModelName;
+    }
+
+    /**
      * Builder to build a text classifier event.
      */
     public static final class Builder {
@@ -359,6 +375,8 @@
         @Nullable private String mLanguage;
         private float mScore;
 
+        private String mModelName;
+
         /**
          * Creates a builder for building {@link TextClassifierEvent}s.
          *
@@ -407,6 +425,7 @@
             return this;
         }
 
+        // TODO: Remove this API.
         /**
          * Sets the time this event occurred. This is the number of milliseconds since
          * January 1, 1970, 00:00:00 GMT. 0 indicates not set.
@@ -501,6 +520,15 @@
         }
 
         /**
+         * Sets the model name string.
+         * @hide
+         */
+        public Builder setModelName(@Nullable String modelVersion) {
+            mModelName = modelVersion;
+            return this;
+        }
+
+        /**
          * Builds and returns a text classifier event.
          */
         @NonNull
@@ -521,7 +549,8 @@
                     mRelativeSuggestedWordEndIndex,
                     mActionIndices,
                     mLanguage,
-                    mScore);
+                    mScore,
+                    mModelName);
         }
         // TODO: Add build(boolean validate).
     }
@@ -544,6 +573,7 @@
         out.append(", mActionIndices=").append(Arrays.toString(mActionIndices));
         out.append(", mLanguage=").append(mLanguage);
         out.append(", mScore=").append(mScore);
+        out.append(", mModelName=").append(mModelName);
         out.append("}");
         return out.toString();
     }
diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
index 5563dfc..6a12250 100644
--- a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
+++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
@@ -16,7 +16,6 @@
 package android.view.textclassifier;
 
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SCORE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE;
@@ -46,7 +45,7 @@
     private final MetricsLogger mMetricsLogger;
 
     public TextClassifierEventTronLogger() {
-        mMetricsLogger = new MetricsLogger();
+        this(new MetricsLogger());
     }
 
     @VisibleForTesting
@@ -57,6 +56,7 @@
     /** Emits a text classifier event to the logs. */
     public void writeEvent(TextClassifierEvent event) {
         Preconditions.checkNotNull(event);
+
         int category = getCategory(event);
         if (category == -1) {
             Log.w(TAG, "Unknown category: " + event.getEventCategory());
@@ -65,14 +65,12 @@
         final LogMaker log = new LogMaker(category)
                 .setSubtype(getLogType(event))
                 .addTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID, event.getResultId())
-                .addTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME, event.getEventTime())
-                .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL,
-                        SelectionSessionLogger.SignatureParser.getModelName(event.getResultId()))
+                .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event))
                 .addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScore());
 
         String[] entityTypes = event.getEntityTypes();
-        // TRON does not support a field of list type, and thus workaround by store them
-        // in three separate fields. This is no longer an issue once we have moved to Westworld.
+        // The old logger does not support a field of list type, and thus workaround by store them
+        // in three separate fields. This is not an issue with the new logger.
         if (entityTypes.length >= 1) {
             log.addTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE, entityTypes[0]);
         }
@@ -93,6 +91,13 @@
         debugLog(log);
     }
 
+    private static String getModelName(TextClassifierEvent event) {
+        if (event.getModelName() != null) {
+            return event.getModelName();
+        }
+        return SelectionSessionLogger.SignatureParser.getModelName(event.getResultId());
+    }
+
     private static int getCategory(TextClassifierEvent event) {
         switch (event.getEventCategory()) {
             case TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS:
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index c297928..14afa33 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -65,9 +65,6 @@
  */
 public final class TextClassifierImpl implements TextClassifier {
 
-    /** @hide */
-    public static final String ACTIONS_INTENTS = "actions-intents";
-
     private static final String LOG_TAG = DEFAULT_LOG_TAG;
 
     private static final boolean DEBUG = false;
@@ -343,7 +340,11 @@
         if (DEBUG) {
             Log.d(DEFAULT_LOG_TAG, "onTextClassifierEvent() called with: event = [" + event + "]");
         }
-        mTextClassifierEventTronLogger.writeEvent(event);
+        try {
+            mTextClassifierEventTronLogger.writeEvent(event);
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "Error writing event", e);
+        }
     }
 
     /** @inheritDoc */
@@ -566,12 +567,16 @@
         final float foreignTextThreshold = mSettings.getLangIdThresholdOverride() >= 0
                 ? mSettings.getLangIdThresholdOverride()
                 : 0.5f /* TODO: Load this from the langId model. */;
+        final Bundle foreignLanguageBundle =
+                detectForeignLanguage(classifiedText, foreignTextThreshold);
+        builder.setForeignLanguageExtra(foreignLanguageBundle);
+
         boolean isPrimaryAction = true;
         final ArrayList<Intent> sourceIntents = new ArrayList<>();
         List<LabeledIntent> labeledIntents = mIntentFactory.create(
                 mContext,
                 classifiedText,
-                isForeignText(classifiedText, foreignTextThreshold),
+                foreignLanguageBundle != null,
                 referenceTime,
                 highestScoringResult);
         for (LabeledIntent labeledIntent : labeledIntents) {
@@ -590,28 +595,28 @@
                                 labeledIntent.getIntent(), labeledIntent.getRequestCode())));
                 isPrimaryAction = false;
             }
-            builder.addAction(action);
-            sourceIntents.add(labeledIntent.getIntent());
+            builder.addAction(action, labeledIntent.getIntent());
         }
 
-        final Bundle extras = new Bundle();
-        extras.putParcelableArrayList(ACTIONS_INTENTS, sourceIntents);
-
-        return builder.setId(createId(text, start, end))
-                .setExtras(extras)
-                .build();
+        return builder.setId(createId(text, start, end)).build();
     }
 
-    private boolean isForeignText(String text, float threshold) {
+    /**
+     * Returns a bundle with the language and confidence score if it finds the text to be
+     * in a foreign language. Otherwise returns null.
+     */
+    @Nullable
+    private Bundle detectForeignLanguage(String text, float threshold) {
         if (threshold > 1) {
-            return false;
+            return null;
         }
 
         // TODO: Revisit this algorithm.
         try {
-            final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text);
+            final LangIdModel langId = getLangIdImpl();
+            final LangIdModel.LanguageResult[] langResults = langId.detectLanguages(text);
             if (langResults.length <= 0) {
-                return false;
+                return null;
             }
 
             LangIdModel.LanguageResult highestScoringResult = langResults[0];
@@ -621,7 +626,7 @@
                 }
             }
             if (highestScoringResult.getScore() < threshold) {
-                return false;
+                return null;
             }
             // TODO: Remove
             Log.d(LOG_TAG, String.format("Language detected: <%s:%s>",
@@ -632,14 +637,15 @@
             final int size = deviceLocales.size();
             for (int i = 0; i < size; i++) {
                 if (deviceLocales.get(i).getLanguage().equals(detected.getLanguage())) {
-                    return false;
+                    return null;
                 }
             }
-            return true;
+            return ExtrasUtils.createForeignLanguageExtra(
+                    detected.getLanguage(), highestScoringResult.getScore(), langId.getVersion());
         } catch (Throwable t) {
             Log.e(LOG_TAG, "Error detecting foreign text. Ignored.", t);
         }
-        return false;
+        return null;
     }
 
     @Override
@@ -773,3 +779,4 @@
         }
     }
 }
+
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4a60b6a..c38566b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4112,9 +4112,9 @@
             }
         }
 
-        private MenuItem addAssistMenuItem(Menu menu, RemoteAction action, int intemId, int order,
+        private MenuItem addAssistMenuItem(Menu menu, RemoteAction action, int itemId, int order,
                 int showAsAction) {
-            final MenuItem item = menu.add(TextView.ID_ASSIST, intemId, order, action.getTitle())
+            final MenuItem item = menu.add(TextView.ID_ASSIST, itemId, order, action.getTitle())
                     .setContentDescription(action.getContentDescription());
             if (action.shouldShowIcon()) {
                 item.setIcon(action.getIcon().loadDrawable(mTextView.getContext()));
@@ -4188,7 +4188,8 @@
 
         @Override
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-            getSelectionActionModeHelper().onSelectionAction(item.getItemId());
+            getSelectionActionModeHelper()
+                    .onSelectionAction(item.getItemId(), item.getTitle().toString());
 
             if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) {
                 return true;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 4caf288..564cfdd 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -20,12 +20,14 @@
 import android.annotation.Nullable;
 import android.annotation.UiThread;
 import android.annotation.WorkerThread;
+import android.app.RemoteAction;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.os.AsyncTask;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.LocaleList;
 import android.text.Layout;
 import android.text.Selection;
@@ -34,13 +36,16 @@
 import android.text.util.Linkify;
 import android.util.Log;
 import android.view.ActionMode;
+import android.view.textclassifier.ExtrasUtils;
 import android.view.textclassifier.SelectionEvent;
 import android.view.textclassifier.SelectionEvent.InvocationMethod;
 import android.view.textclassifier.SelectionSessionLogger;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationConstants;
+import android.view.textclassifier.TextClassificationContext;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextClassifierEvent;
 import android.view.textclassifier.TextSelection;
 import android.widget.Editor.SelectionModifierCursorController;
 
@@ -166,16 +171,17 @@
         }
     }
 
-    public void onSelectionAction(int menuItemId) {
+    /** Reports a selection action event. */
+    public void onSelectionAction(int menuItemId, @Nullable String actionLabel) {
         mSelectionTracker.onSelectionAction(
                 mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
-                getActionType(menuItemId), mTextClassification);
+                getActionType(menuItemId), actionLabel, mTextClassification);
     }
 
     public void onSelectionDrag() {
         mSelectionTracker.onSelectionAction(
                 mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
-                SelectionEvent.ACTION_DRAG, mTextClassification);
+                SelectionEvent.ACTION_DRAG, /* actionLabel= */ null, mTextClassification);
     }
 
     public void onTextChanged(int start, int end) {
@@ -511,8 +517,11 @@
             mOriginalEnd = mSelectionEnd = selectionEnd;
             mAllowReset = false;
             maybeInvalidateLogger();
-            mLogger.logSelectionStarted(mTextView.getTextClassificationSession(),
-                    text, selectionStart,
+            mLogger.logSelectionStarted(
+                    mTextView.getTextClassificationSession(),
+                    mTextView.getTextClassificationContext(),
+                    text,
+                    selectionStart,
                     isLink ? SelectionEvent.INVOCATION_LINK : SelectionEvent.INVOCATION_MANUAL);
         }
 
@@ -570,10 +579,12 @@
         public void onSelectionAction(
                 int selectionStart, int selectionEnd,
                 @SelectionEvent.ActionType int action,
+                @Nullable String actionLabel,
                 @Nullable TextClassification classification) {
             if (isSelectionStarted()) {
                 mAllowReset = false;
-                mLogger.logSelectionAction(selectionStart, selectionEnd, action, classification);
+                mLogger.logSelectionAction(
+                        selectionStart, selectionEnd, action, actionLabel, classification);
             }
         }
 
@@ -596,7 +607,8 @@
                     mSelectionEnd = editor.getTextView().getSelectionEnd();
                     mLogger.logSelectionAction(
                             textView.getSelectionStart(), textView.getSelectionEnd(),
-                            SelectionEvent.ACTION_RESET, null /* classification */);
+                            SelectionEvent.ACTION_RESET,
+                            /* actionLabel= */ null, /* classification= */ null);
                 }
                 return selected;
             }
@@ -605,7 +617,9 @@
 
         public void onTextChanged(int start, int end, TextClassification classification) {
             if (isSelectionStarted() && start == mSelectionStart && end == mSelectionEnd) {
-                onSelectionAction(start, end, SelectionEvent.ACTION_OVERTYPE, classification);
+                onSelectionAction(
+                        start, end, SelectionEvent.ACTION_OVERTYPE,
+                        /* actionLabel= */ null, classification);
             }
         }
 
@@ -644,7 +658,8 @@
                 if (mIsPending) {
                     mLogger.logSelectionAction(
                             mSelectionStart, mSelectionEnd,
-                            SelectionEvent.ACTION_ABANDON, null /* classification */);
+                            SelectionEvent.ACTION_ABANDON,
+                            /* actionLabel= */ null, /* classification= */ null);
                     mSelectionStart = mSelectionEnd = -1;
                     mLogger.endTextClassificationSession();
                     mIsPending = false;
@@ -679,6 +694,11 @@
         private final BreakIterator mTokenIterator;
 
         @Nullable private TextClassifier mClassificationSession;
+        @Nullable private TextClassificationContext mClassificationContext;
+
+        @Nullable private TextClassifierEvent mTranslateViewEvent;
+        @Nullable private TextClassifierEvent mTranslateClickEvent;
+
         private int mStartIndex;
         private String mText;
 
@@ -690,6 +710,7 @@
 
         public void logSelectionStarted(
                 TextClassifier classificationSession,
+                TextClassificationContext classificationContext,
                 CharSequence text, int index,
                 @InvocationMethod int invocationMethod) {
             try {
@@ -701,6 +722,7 @@
                 mTokenIterator.setText(mText);
                 mStartIndex = index;
                 mClassificationSession = classificationSession;
+                mClassificationContext = classificationContext;
                 if (hasActiveClassificationSession()) {
                     mClassificationSession.onSelectionEvent(
                             SelectionEvent.createSelectionStartedEvent(invocationMethod, 0));
@@ -731,6 +753,7 @@
                                 SelectionEvent.createSelectionModifiedEvent(
                                         wordIndices[0], wordIndices[1]));
                     }
+                    maybeGenerateTranslateViewEvent(classification);
                 }
             } catch (Exception e) {
                 // Avoid crashes due to logging.
@@ -741,6 +764,7 @@
         public void logSelectionAction(
                 int start, int end,
                 @SelectionEvent.ActionType int action,
+                @Nullable String actionLabel,
                 @Nullable TextClassification classification) {
             try {
                 if (hasActiveClassificationSession()) {
@@ -757,6 +781,9 @@
                                 SelectionEvent.createSelectionActionEvent(
                                         wordIndices[0], wordIndices[1], action));
                     }
+
+                    maybeGenerateTranslateClickEvent(classification, actionLabel);
+
                     if (SelectionEvent.isTerminal(action)) {
                         endTextClassificationSession();
                     }
@@ -773,6 +800,7 @@
 
         public void endTextClassificationSession() {
             if (hasActiveClassificationSession()) {
+                maybeReportTranslateEvents();
                 mClassificationSession.destroy();
             }
         }
@@ -843,6 +871,78 @@
         private boolean isWhitespace(int start, int end) {
             return PATTERN_WHITESPACE.matcher(mText.substring(start, end)).matches();
         }
+
+        private void maybeGenerateTranslateViewEvent(@Nullable TextClassification classification) {
+            if (classification != null) {
+                final TextClassifierEvent event = generateTranslateEvent(
+                        TextClassifierEvent.TYPE_ACTIONS_SHOWN,
+                        classification, mClassificationContext, /* actionLabel= */null);
+                mTranslateViewEvent = (event != null) ? event : mTranslateViewEvent;
+            }
+        }
+
+        private void maybeGenerateTranslateClickEvent(
+                @Nullable TextClassification classification, String actionLabel) {
+            if (classification != null) {
+                mTranslateClickEvent = generateTranslateEvent(
+                        TextClassifierEvent.TYPE_SMART_ACTION,
+                        classification, mClassificationContext, actionLabel);
+            }
+        }
+
+        private void maybeReportTranslateEvents() {
+            // Translate view and click events should only be logged once per selection session.
+            if (mTranslateViewEvent != null) {
+                mClassificationSession.onTextClassifierEvent(mTranslateViewEvent);
+                mTranslateViewEvent = null;
+            }
+            if (mTranslateClickEvent != null) {
+                mClassificationSession.onTextClassifierEvent(mTranslateClickEvent);
+                mTranslateClickEvent = null;
+            }
+        }
+
+        @Nullable
+        private static TextClassifierEvent generateTranslateEvent(
+                int eventType, TextClassification classification,
+                TextClassificationContext classificationContext, @Nullable String actionLabel) {
+
+            // The platform attempts to log "views" and "clicks" of the "Translate" action.
+            // Views are logged if a user is presented with the translate action during a selection
+            // session.
+            // Clicks are logged if the user clicks on the translate action.
+            // The index of the translate action is also logged to indicate whether it might have
+            // been in the main panel or overflow panel of the selection toolbar.
+            // NOTE that the "views" metric may be flawed if a TextView removes the translate menu
+            // item via a custom action mode callback or does not show a selection menu item.
+
+            final RemoteAction translateAction = ExtrasUtils.findTranslateAction(classification);
+            if (translateAction == null) {
+                // No translate action present. Nothing to log. Exit.
+                return null;
+            }
+
+            if (eventType == TextClassifierEvent.TYPE_SMART_ACTION
+                    && !translateAction.getTitle().toString().equals(actionLabel)) {
+                // Clicked action is not a translate action. Nothing to log. Exit.
+                // Note that we don't expect an actionLabel for "view" events.
+                return null;
+            }
+
+            final Bundle foreignLanguageExtra = ExtrasUtils.getForeignLanguageExtra(classification);
+            final String language = ExtrasUtils.getEntityType(foreignLanguageExtra);
+            final float score = ExtrasUtils.getScore(foreignLanguageExtra);
+            final String model = ExtrasUtils.getModelName(foreignLanguageExtra);
+            return new TextClassifierEvent.Builder(
+                    TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType)
+                    .setEventContext(classificationContext)
+                    .setResultId(classification.getId())
+                    .setEntityTypes(language)
+                    .setScore(score)
+                    .setActionIndices(classification.getActions().indexOf(translateAction))
+                    .setModelName(model)
+                    .build();
+        }
     }
 
     /**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2b45c06..8029cf0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -456,6 +456,7 @@
 
     private TextClassifier mTextClassifier;
     private TextClassifier mTextClassificationSession;
+    private TextClassificationContext mTextClassificationContext;
 
     // A flag to prevent repeated movements from escaping the enclosing text view. The idea here is
     // that if a user is holding down a movement key to traverse text, we shouldn't also traverse
@@ -12068,16 +12069,15 @@
                 } else {
                     widgetType = TextClassifier.WIDGET_TYPE_UNSELECTABLE_TEXTVIEW;
                 }
-                final TextClassificationContext textClassificationContext =
-                        new TextClassificationContext.Builder(
-                                mContext.getPackageName(), widgetType)
-                                .build();
+                mTextClassificationContext = new TextClassificationContext.Builder(
+                        mContext.getPackageName(), widgetType)
+                        .build();
                 if (mTextClassifier != null) {
                     mTextClassificationSession = tcm.createTextClassificationSession(
-                            textClassificationContext, mTextClassifier);
+                            mTextClassificationContext, mTextClassifier);
                 } else {
                     mTextClassificationSession = tcm.createTextClassificationSession(
-                            textClassificationContext);
+                            mTextClassificationContext);
                 }
             } else {
                 mTextClassificationSession = TextClassifier.NO_OP;
@@ -12087,6 +12087,15 @@
     }
 
     /**
+     * Returns the {@link TextClassificationContext} for the current TextClassifier session.
+     * @see #getTextClassificationSession()
+     */
+    @Nullable
+    TextClassificationContext getTextClassificationContext() {
+        return mTextClassificationContext;
+    }
+
+    /**
      * Returns true if this TextView uses a no-op TextClassifier.
      */
     boolean usesNoOpTextClassifier() {
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
new file mode 100644
index 0000000..9283105
--- /dev/null
+++ b/core/java/com/android/internal/os/OWNERS
@@ -0,0 +1 @@
+per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index a365a56..86342c4 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -4,3 +4,6 @@
 
 # Connectivity
 per-file android_net_* = ek@google.com, lorenzo@google.com, satk@google.com
+
+# Zygote
+per-file com_android_inernal_os_Zygote.*,fd_utils.* = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
diff --git a/core/jni/android_media_AudioAttributes.cpp b/core/jni/android_media_AudioAttributes.cpp
index 4be4def..b87a34d 100644
--- a/core/jni/android_media_AudioAttributes.cpp
+++ b/core/jni/android_media_AudioAttributes.cpp
@@ -135,7 +135,7 @@
 {
     audio_attributes_t *aa = new (calloc(1, sizeof(audio_attributes_t)))
                 audio_attributes_t{AUDIO_ATTRIBUTES_INITIALIZER};
-    return UniqueAaPtr{aa, free};
+    return UniqueAaPtr{aa};
 }
 
 jint JNIAudioAttributeHelper::nativeFromJava(JNIEnv* env, jobject jAudioAttributes,
diff --git a/core/jni/android_media_AudioAttributes.h b/core/jni/android_media_AudioAttributes.h
index c558352..628f7e3 100644
--- a/core/jni/android_media_AudioAttributes.h
+++ b/core/jni/android_media_AudioAttributes.h
@@ -27,7 +27,11 @@
 class JNIAudioAttributeHelper
 {
 public:
-    using UniqueAaPtr = std::unique_ptr<audio_attributes_t, decltype(free)*>;
+    struct FreeDeleter {
+        void operator()(void *p) const { ::free(p); }
+    };
+
+    using UniqueAaPtr = std::unique_ptr<audio_attributes_t, FreeDeleter>;
 
     /**
      * @brief makeUnique helper to prevent leak
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 79afe69..0dc54e0 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -374,7 +374,9 @@
     <style name="TextAppearance.DeviceDefault.Caption" parent="TextAppearance.Material.Caption">
         <item name="fontFamily">@string/config_bodyFontFamily</item>
     </style>
-    <style name="TextAppearance.DeviceDefault.ListItem" parent="TextAppearance.DeviceDefault.Subhead"/>
+    <style name="TextAppearance.DeviceDefault.ListItem" parent="TextAppearance.DeviceDefault.Subhead">
+        <item name="fontFamily">@string/config_headlineFontFamily</item>
+    </style>
     <style name="TextAppearance.DeviceDefault.ListItemSecondary" parent="TextAppearance.DeviceDefault.Body1"/>
 
     <!-- Preference Styles -->
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 5e58f82..582be9d 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -21,8 +21,10 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
+import android.app.RemoteAction;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.LocaleList;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -246,25 +248,31 @@
     public void testClassifyText_foreignText() {
         LocaleList originalLocales = LocaleList.getDefault();
         LocaleList.setDefault(LocaleList.forLanguageTags("en"));
-        String foreignText = "これは日本語のテキストです";
+        String japaneseText = "これは日本語のテキストです";
 
         Context context = new FakeContextBuilder()
                 .setIntentComponent(Intent.ACTION_TRANSLATE, FakeContextBuilder.DEFAULT_COMPONENT)
                 .build();
         TextClassifier classifier = new TextClassifierImpl(context, TC_CONSTANTS);
         TextClassification.Request request = new TextClassification.Request.Builder(
-                foreignText, 0, foreignText.length())
+                japaneseText, 0, japaneseText.length())
                 .setDefaultLocales(LOCALES)
                 .build();
 
         TextClassification classification = classifier.classifyText(request);
+        RemoteAction translateAction = classification.getActions().get(0);
         assertEquals(1, classification.getActions().size());
         assertEquals(
                 context.getString(com.android.internal.R.string.translate),
-                classification.getActions().get(0).getTitle());
-        Intent intent = (Intent) classification.getExtras()
-                .getParcelableArrayList(TextClassifierImpl.ACTIONS_INTENTS).get(0);
+                translateAction.getTitle());
+
+        assertEquals(translateAction, ExtrasUtils.findTranslateAction(classification));
+        Intent intent = ExtrasUtils.getActionsIntents(classification).get(0);
         assertEquals(Intent.ACTION_TRANSLATE, intent.getAction());
+        Bundle foreignLanguageInfo = ExtrasUtils.getForeignLanguageExtra(classification);
+        assertEquals("ja", ExtrasUtils.getEntityType(foreignLanguageInfo));
+        assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) >= 0);
+        assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) <= 1);
 
         LocaleList.setDefault(originalLocales);
     }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 59c6a0a..63b57d1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -181,22 +181,14 @@
         "android.location.GPS_ENABLED_CHANGE";
 
     /**
-     * Broadcast intent action when the configured location providers
-     * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the
-     * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION}
-     * instead.
+     * Broadcast intent action when the set of enabled location providers changes. To check the
+     * status of a provider, use {@link #isProviderEnabled(String)}.
      */
-    public static final String PROVIDERS_CHANGED_ACTION =
-        "android.location.PROVIDERS_CHANGED";
+    public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
 
     /**
-     * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes.
-     * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
-     * If you're interacting with {@link #isProviderEnabled(String)}, use
-     * {@link #PROVIDERS_CHANGED_ACTION} instead.
-     *
-     * In the future, there may be mode changes that do not result in
-     * {@link #PROVIDERS_CHANGED_ACTION} broadcasts.
+     * Broadcast intent action when the device location mode changes. To check the location mode,
+     * use {@link #isLocationEnabled()}.
      */
     public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
 
@@ -207,8 +199,10 @@
      * If you're interacting with {@link #isProviderEnabled(String)}, use
      * {@link #PROVIDERS_CHANGED_ACTION} instead.
      *
+     * @deprecated Do not use.
      * @hide
      */
+    @Deprecated
     public static final String MODE_CHANGING_ACTION = "com.android.settings.location.MODE_CHANGING";
 
     /**
@@ -299,7 +293,7 @@
             "com.android.settings.location.FOOTER_STRING";
 
     // Map from LocationListeners to their associated ListenerTransport objects
-    private HashMap<LocationListener,ListenerTransport> mListeners =
+    private final HashMap<LocationListener, ListenerTransport> mListeners =
         new HashMap<LocationListener,ListenerTransport>();
 
     private class ListenerTransport extends ILocationListener.Stub {
@@ -1264,39 +1258,20 @@
     }
 
     /**
-     * Returns the current enabled/disabled status of location
+     * Returns the current enabled/disabled state of location. To listen for changes, see
+     * {@link #MODE_CHANGED_ACTION}.
      *
-     * @return true if location is enabled. false if location is disabled.
+     * @return true if location is enabled and false if location is disabled.
      */
     public boolean isLocationEnabled() {
         return isLocationEnabledForUser(Process.myUserHandle());
     }
 
     /**
-     * Method for enabling or disabling location.
-     *
-     * @param enabled true to enable location. false to disable location
-     * @param userHandle the user to set
-     *
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(WRITE_SECURE_SETTINGS)
-    public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
-        Settings.Secure.putIntForUser(
-                mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE,
-                enabled
-                        ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
-                        : Settings.Secure.LOCATION_MODE_OFF,
-                userHandle.getIdentifier());
-    }
-
-    /**
-     * Returns the current enabled/disabled status of location
+     * Returns the current enabled/disabled state of location.
      *
      * @param userHandle the user to query
-     * @return true location is enabled. false if location is disabled.
+     * @return true if location is enabled and false if location is disabled.
      *
      * @hide
      */
@@ -1310,19 +1285,32 @@
     }
 
     /**
-     * Returns the current enabled/disabled status of the given provider.
+     * Enables or disables the location setting.
      *
-     * <p>If the user has enabled this provider in the Settings menu, true
-     * is returned otherwise false is returned
+     * @param enabled true to enable location and false to disable location.
+     * @param userHandle the user to set
      *
-     * <p>Callers should instead use {@link #isLocationEnabled()}
-     * unless they depend on provider-specific APIs such as
-     * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(WRITE_SECURE_SETTINGS)
+    public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
+        Settings.Secure.putIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.LOCATION_MODE,
+                enabled
+                        ? Settings.Secure.LOCATION_MODE_ON
+                        : Settings.Secure.LOCATION_MODE_OFF,
+                userHandle.getIdentifier());
+    }
+
+    /**
+     * Returns the current enabled/disabled status of the given provider. To listen for changes, see
+     * {@link #PROVIDERS_CHANGED_ACTION}.
      *
-     * <p>
-     * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this
-     * method would throw {@link SecurityException} if the location permissions
-     * were not sufficient to use the specified provider.
+     * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method would throw
+     * {@link SecurityException} if the location permissions were not sufficient to use the
+     * specified provider.
      *
      * @param provider the name of the provider
      * @return true if the provider exists and is enabled
@@ -1334,19 +1322,13 @@
     }
 
     /**
-     * Returns the current enabled/disabled status of the given provider and user.
+     * Returns the current enabled/disabled status of the given provider and user. Callers should
+     * prefer {@link #isLocationEnabledForUser(UserHandle)} unless they depend on provider-specific
+     * APIs.
      *
-     * <p>If the user has enabled this provider in the Settings menu, true
-     * is returned otherwise false is returned
-     *
-     * <p>Callers should instead use {@link #isLocationEnabled()}
-     * unless they depend on provider-specific APIs such as
-     * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
-     *
-     * <p>
-     * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this
-     * method would throw {@link SecurityException} if the location permissions
-     * were not sufficient to use the specified provider.
+     * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method would throw
+     * {@link SecurityException} if the location permissions were not sufficient to use the
+     * specified provider.
      *
      * @param provider the name of the provider
      * @param userHandle the user to query
@@ -1367,12 +1349,14 @@
     }
 
     /**
-     * Method for enabling or disabling a single location provider.
+     * Method for enabling or disabling a single location provider. This method is deprecated and
+     * functions as a best effort. It should not be relied on in any meaningful sense as providers
+     * may no longer be enabled or disabled by clients.
      *
      * @param provider the name of the provider
      * @param enabled true to enable the provider. false to disable the provider
      * @param userHandle the user to set
-     * @return true if the value was set, false on database errors
+     * @return true if the value was set, false otherwise
      *
      * @throws IllegalArgumentException if provider is null
      * @deprecated Do not manipulate providers individually, use
diff --git a/media/Android.bp b/media/Android.bp
index e7d5faf..d7b8dd2 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -1,30 +1,4 @@
 java_library {
-    name: "updatable-media1",
-
-    srcs: [
-        ":media1-srcs",
-        ":framework-media-annotation-srcs",
-    ],
-
-    aidl: {
-        export_include_dirs: [
-            "apex/java",
-        ],
-
-        // TODO: find out a way to include only the necessary aidl files instead of dirs.
-        include_dirs: [
-            "frameworks/base/core/java",
-            "frameworks/base/media/java",
-        ],
-    },
-
-    installable: true,
-
-    // Make sure that the implementaion only relies on SDK or system APIs.
-    sdk_version: "system_current",
-}
-
-java_library {
     name: "updatable-media",
 
     srcs: [
@@ -57,55 +31,12 @@
 filegroup {
     name: "media-srcs-without-aidls",
     srcs : [
-        ":media1-srcs-without-aidls",
         ":mediasession2-srcs-without-aidls",
         ":mediaplayer2-srcs",
     ],
 }
 
 filegroup {
-    name: "media1-srcs",
-    srcs: [
-        "apex/java/android/media/MediaDescription.java",
-        "apex/java/android/media/MediaParceledListSlice.java",
-        "apex/java/android/media/Rating.java",
-        "apex/java/android/media/VolumeProvider.java",
-        "apex/java/android/media/browse/MediaBrowser.java",
-        "apex/java/android/media/browse/MediaBrowserUtils.java",
-        "apex/java/android/media/session/ControllerCallbackLink.java",
-        "apex/java/android/media/session/ControllerLink.java",
-        "apex/java/android/media/session/ISession.aidl",
-        "apex/java/android/media/session/ISessionCallback.aidl",
-        "apex/java/android/media/session/ISessionController.aidl",
-        "apex/java/android/media/session/ISessionControllerCallback.aidl",
-        "apex/java/android/media/session/MediaController.java",
-        "apex/java/android/media/session/MediaSessionEngine.java",
-        "apex/java/android/media/session/MediaSessionProviderService.java",
-        "apex/java/android/media/session/PlaybackState.java",
-        "apex/java/android/media/session/SessionCallbackLink.java",
-        "apex/java/android/media/session/SessionLink.java",
-        "apex/java/android/service/media/IMediaBrowserService.aidl",
-        "apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl",
-        "apex/java/android/service/media/MediaBrowserService.java",
-    ],
-}
-
-filegroup {
-    name: "media1-srcs-without-aidls",
-    srcs: [
-        ":media1-srcs",
-    ],
-    exclude_srcs: [
-        "apex/java/android/media/session/ISession.aidl",
-        "apex/java/android/media/session/ISessionCallback.aidl",
-        "apex/java/android/media/session/ISessionController.aidl",
-        "apex/java/android/media/session/ISessionControllerCallback.aidl",
-        "apex/java/android/service/media/IMediaBrowserService.aidl",
-        "apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl",
-    ],
-}
-
-filegroup {
     name: "mediasession2-srcs",
     srcs: [
         "apex/java/android/media/Controller2Link.java",
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 87ce4c3..0fd496b 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -3668,53 +3668,66 @@
     }
 
     /**
-     * The status codes for {@link DrmEventCallback#onDrmPrepared} listener.
+     * A status code for {@link DrmEventCallback#onDrmPrepared} listener.
      * <p>
      *
      * DRM preparation has succeeded.
-     * @hide
      */
     public static final int PREPARE_DRM_STATUS_SUCCESS = 0;
 
     /**
+     * A status code for {@link DrmEventCallback#onDrmPrepared} listener.
+     * <p>
+     *
      * The device required DRM provisioning but couldn't reach the provisioning server.
-     * @hide
      */
     public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1;
 
     /**
+     * A status code for {@link DrmEventCallback#onDrmPrepared} listener.
+     * <p>
+     *
      * The device required DRM provisioning but the provisioning server denied the request.
-     * @hide
      */
     public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2;
 
     /**
+     * A status code for {@link DrmEventCallback#onDrmPrepared} listener.
+     * <p>
+     *
      * The DRM preparation has failed .
-     * @hide
      */
     public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3;
 
     /**
+     * A status code for {@link DrmEventCallback#onDrmPrepared} listener.
+     * <p>
+     *
      * The crypto scheme UUID is not supported by the device.
-     * @hide
      */
     public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4;
 
     /**
+     * A status code for {@link DrmEventCallback#onDrmPrepared} listener.
+     * <p>
+     *
      * The hardware resources are not available, due to being in use.
-     * @hide
      */
     public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5;
 
     /**
+     * A status code for {@link DrmEventCallback#onDrmPrepared} listener.
+     * <p>
+     *
      * Restoring persisted offline keys failed.
-     * @hide
      */
     public static final int PREPARE_DRM_STATUS_RESTORE_ERROR = 6;
 
     /**
+     * A status code for {@link DrmEventCallback#onDrmPrepared} listener.
+     * <p>
+     *
      * Error during key request/response exchange with license server.
-     * @hide
      */
     public static final int PREPARE_DRM_STATUS_KEY_EXCHANGE_ERROR = 7;
 
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index f756658..0c3d625 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3314,7 +3314,7 @@
      */
     public void setAudioPresentation(@NonNull AudioPresentation presentation) {
         if (presentation == null) {
-            throw new IllegalArgumentException("audio presentation is null");
+            throw new NullPointerException("audio presentation is null");
         }
         native_setAudioPresentation(presentation.getPresentationId(), presentation.getProgramId());
     }
diff --git a/media/apex/java/android/media/MediaDescription.aidl b/media/java/android/media/MediaDescription.aidl
similarity index 100%
rename from media/apex/java/android/media/MediaDescription.aidl
rename to media/java/android/media/MediaDescription.aidl
diff --git a/media/apex/java/android/media/MediaDescription.java b/media/java/android/media/MediaDescription.java
similarity index 100%
rename from media/apex/java/android/media/MediaDescription.java
rename to media/java/android/media/MediaDescription.java
diff --git a/media/apex/java/android/media/MediaParceledListSlice.aidl b/media/java/android/media/MediaParceledListSlice.aidl
similarity index 100%
rename from media/apex/java/android/media/MediaParceledListSlice.aidl
rename to media/java/android/media/MediaParceledListSlice.aidl
diff --git a/media/apex/java/android/media/MediaParceledListSlice.java b/media/java/android/media/MediaParceledListSlice.java
similarity index 100%
rename from media/apex/java/android/media/MediaParceledListSlice.java
rename to media/java/android/media/MediaParceledListSlice.java
diff --git a/media/apex/java/android/media/Rating.aidl b/media/java/android/media/Rating.aidl
similarity index 100%
rename from media/apex/java/android/media/Rating.aidl
rename to media/java/android/media/Rating.aidl
diff --git a/media/apex/java/android/media/Rating.java b/media/java/android/media/Rating.java
similarity index 100%
rename from media/apex/java/android/media/Rating.java
rename to media/java/android/media/Rating.java
diff --git a/media/apex/java/android/media/VolumeProvider.java b/media/java/android/media/VolumeProvider.java
similarity index 100%
rename from media/apex/java/android/media/VolumeProvider.java
rename to media/java/android/media/VolumeProvider.java
diff --git a/media/apex/java/android/media/browse/MediaBrowser.aidl b/media/java/android/media/browse/MediaBrowser.aidl
similarity index 100%
rename from media/apex/java/android/media/browse/MediaBrowser.aidl
rename to media/java/android/media/browse/MediaBrowser.aidl
diff --git a/media/apex/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
similarity index 100%
rename from media/apex/java/android/media/browse/MediaBrowser.java
rename to media/java/android/media/browse/MediaBrowser.java
diff --git a/media/apex/java/android/media/browse/MediaBrowserUtils.java b/media/java/android/media/browse/MediaBrowserUtils.java
similarity index 100%
rename from media/apex/java/android/media/browse/MediaBrowserUtils.java
rename to media/java/android/media/browse/MediaBrowserUtils.java
diff --git a/media/apex/java/android/media/session/ControllerCallbackLink.aidl b/media/java/android/media/session/ControllerCallbackLink.aidl
similarity index 100%
rename from media/apex/java/android/media/session/ControllerCallbackLink.aidl
rename to media/java/android/media/session/ControllerCallbackLink.aidl
diff --git a/media/apex/java/android/media/session/ControllerCallbackLink.java b/media/java/android/media/session/ControllerCallbackLink.java
similarity index 100%
rename from media/apex/java/android/media/session/ControllerCallbackLink.java
rename to media/java/android/media/session/ControllerCallbackLink.java
diff --git a/media/apex/java/android/media/session/ControllerLink.aidl b/media/java/android/media/session/ControllerLink.aidl
similarity index 100%
rename from media/apex/java/android/media/session/ControllerLink.aidl
rename to media/java/android/media/session/ControllerLink.aidl
diff --git a/media/apex/java/android/media/session/ControllerLink.java b/media/java/android/media/session/ControllerLink.java
similarity index 100%
rename from media/apex/java/android/media/session/ControllerLink.java
rename to media/java/android/media/session/ControllerLink.java
diff --git a/media/apex/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
similarity index 100%
rename from media/apex/java/android/media/session/ISession.aidl
rename to media/java/android/media/session/ISession.aidl
diff --git a/media/apex/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
similarity index 100%
rename from media/apex/java/android/media/session/ISessionCallback.aidl
rename to media/java/android/media/session/ISessionCallback.aidl
diff --git a/media/apex/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
similarity index 100%
rename from media/apex/java/android/media/session/ISessionController.aidl
rename to media/java/android/media/session/ISessionController.aidl
diff --git a/media/apex/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
similarity index 100%
rename from media/apex/java/android/media/session/ISessionControllerCallback.aidl
rename to media/java/android/media/session/ISessionControllerCallback.aidl
diff --git a/media/apex/java/android/media/session/MediaController.aidl b/media/java/android/media/session/MediaController.aidl
similarity index 100%
rename from media/apex/java/android/media/session/MediaController.aidl
rename to media/java/android/media/session/MediaController.aidl
diff --git a/media/apex/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
similarity index 100%
rename from media/apex/java/android/media/session/MediaController.java
rename to media/java/android/media/session/MediaController.java
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index ca3346c..03627de 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -142,10 +142,9 @@
         MediaSessionManager manager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         try {
-            MediaSessionEngine.CallbackStub cbStub = new MediaSessionEngine.CallbackStub();
-            SessionCallbackLink cbLink = new SessionCallbackLink(context, cbStub);
+            SessionCallbackLink cbLink = new SessionCallbackLink(context);
             SessionLink sessionLink = manager.createSession(cbLink, tag);
-            mImpl = new MediaSessionEngine(context, sessionLink, cbLink, cbStub);
+            mImpl = new MediaSessionEngine(context, sessionLink, cbLink);
             mMaxBitmapSize = context.getResources().getDimensionPixelSize(
                     android.R.dimen.config_mediaMetadataBitmapMaxSize);
         } catch (RuntimeException e) {
diff --git a/media/apex/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java
similarity index 78%
rename from media/apex/java/android/media/session/MediaSessionEngine.java
rename to media/java/android/media/session/MediaSessionEngine.java
index 31714e1..7fea90d 100644
--- a/media/apex/java/android/media/session/MediaSessionEngine.java
+++ b/media/java/android/media/session/MediaSessionEngine.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -44,7 +43,6 @@
 import android.view.KeyEvent;
 import android.view.ViewConfiguration;
 
-import java.lang.ref.WeakReference;
 import java.util.List;
 import java.util.Objects;
 
@@ -60,10 +58,7 @@
     private final MediaSession.Token mSessionToken;
     private final MediaController mController;
     private final SessionLink mSessionLink;
-    private final SessionCallbackLink mCbLink;
 
-    // Do not change the name of mCallbackWrapper. Support lib accesses this by using reflection.
-    @UnsupportedAppUsage
     private CallbackMessageHandler mCallbackHandler;
     private VolumeProvider mVolumeProvider;
     private PlaybackState mPlaybackState;
@@ -78,14 +73,12 @@
      *
      * @param context The context to use to create the session.
      * @param sessionLink A session link for the binder of MediaSessionRecord
-     * @param cbStub A callback link that handles incoming command to {@link MediaSession.Callback}.
      */
     public MediaSessionEngine(@NonNull Context context, @NonNull SessionLink sessionLink,
-            @NonNull SessionCallbackLink cbLink, @NonNull CallbackStub cbStub) {
+            @NonNull SessionCallbackLink cbLink) {
         mSessionLink = sessionLink;
-        mCbLink = cbLink;
 
-        cbStub.setSessionImpl(this);
+        cbLink.setSessionEngine(this);
         mSessionToken = new MediaSession.Token(mSessionLink.getController());
         mController = new MediaController(context, mSessionToken);
     }
@@ -479,97 +472,97 @@
         }
     }
 
-    private void dispatchPrepare(RemoteUserInfo caller) {
+    void dispatchPrepare(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
     }
 
-    private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+    void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
         postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
     }
 
-    private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+    void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
         postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
     }
 
-    private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+    void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
         postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
     }
 
-    private void dispatchPlay(RemoteUserInfo caller) {
+    void dispatchPlay(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
     }
 
-    private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+    void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
         postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
     }
 
-    private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+    void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
         postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
     }
 
-    private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+    void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
         postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
     }
 
-    private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
+    void dispatchSkipToItem(RemoteUserInfo caller, long id) {
         postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
     }
 
-    private void dispatchPause(RemoteUserInfo caller) {
+    void dispatchPause(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
     }
 
-    private void dispatchStop(RemoteUserInfo caller) {
+    void dispatchStop(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
     }
 
-    private void dispatchNext(RemoteUserInfo caller) {
+    void dispatchNext(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
     }
 
-    private void dispatchPrevious(RemoteUserInfo caller) {
+    void dispatchPrevious(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
     }
 
-    private void dispatchFastForward(RemoteUserInfo caller) {
+    void dispatchFastForward(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
     }
 
-    private void dispatchRewind(RemoteUserInfo caller) {
+    void dispatchRewind(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
     }
 
-    private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
+    void dispatchSeekTo(RemoteUserInfo caller, long pos) {
         postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
     }
 
-    private void dispatchRate(RemoteUserInfo caller, Rating rating) {
+    void dispatchRate(RemoteUserInfo caller, Rating rating) {
         postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
     }
 
-    private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
+    void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
         postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
     }
 
-    private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
+    void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
         postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
     }
 
-    private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
+    void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
             long delay) {
         postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
                 mediaButtonIntent, null, delay);
     }
 
-    private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
+    void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
         postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
     }
 
-    private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
+    void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
         postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
     }
 
-    private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
+    void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
             ResultReceiver resultCb) {
         Command cmd = new Command(command, args, resultCb);
         postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
@@ -979,259 +972,7 @@
         }
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
-    public static final class CallbackStub extends SessionCallbackLink.CallbackStub {
-        private WeakReference<MediaSessionEngine> mSessionImpl;
-
-        private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid) {
-            return new RemoteUserInfo(packageName, pid, uid);
-        }
-
-        public CallbackStub() {
-        }
-
-        @Override
-        public void onCommand(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchCommand(createRemoteUserInfo(packageName, pid, uid),
-                        command, args, cb);
-            }
-        }
-
-        @Override
-        public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
-                int sequenceNumber, ResultReceiver cb) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            try {
-                if (sessionImpl != null) {
-                    sessionImpl.dispatchMediaButton(
-                            createRemoteUserInfo(packageName, pid, uid), mediaButtonIntent);
-                }
-            } finally {
-                if (cb != null) {
-                    cb.send(sequenceNumber, null);
-                }
-            }
-        }
-
-        @Override
-        public void onMediaButtonFromController(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Intent mediaButtonIntent) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid),
-                        mediaButtonIntent);
-            }
-        }
-
-        @Override
-        public void onPrepare(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid));
-            }
-        }
-
-        @Override
-        public void onPrepareFromMediaId(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String mediaId,
-                Bundle extras) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPrepareFromMediaId(
-                        createRemoteUserInfo(packageName, pid, uid), mediaId, extras);
-            }
-        }
-
-        @Override
-        public void onPrepareFromSearch(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String query,
-                Bundle extras) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPrepareFromSearch(
-                        createRemoteUserInfo(packageName, pid, uid), query, extras);
-            }
-        }
-
-        @Override
-        public void onPrepareFromUri(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Uri uri, Bundle extras) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPrepareFromUri(
-                        createRemoteUserInfo(packageName, pid, uid), uri, extras);
-            }
-        }
-
-        @Override
-        public void onPlay(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPlay(createRemoteUserInfo(packageName, pid, uid));
-            }
-        }
-
-        @Override
-        public void onPlayFromMediaId(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String mediaId,
-                Bundle extras) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPlayFromMediaId(
-                        createRemoteUserInfo(packageName, pid, uid), mediaId, extras);
-            }
-        }
-
-        @Override
-        public void onPlayFromSearch(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String query,
-                Bundle extras) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPlayFromSearch(
-                        createRemoteUserInfo(packageName, pid, uid), query, extras);
-            }
-        }
-
-        @Override
-        public void onPlayFromUri(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Uri uri, Bundle extras) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPlayFromUri(
-                        createRemoteUserInfo(packageName, pid, uid), uri, extras);
-            }
-        }
-
-        @Override
-        public void onSkipToTrack(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, long id) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchSkipToItem(
-                        createRemoteUserInfo(packageName, pid, uid), id);
-            }
-        }
-
-        @Override
-        public void onPause(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPause(createRemoteUserInfo(packageName, pid, uid));
-            }
-        }
-
-        @Override
-        public void onStop(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchStop(createRemoteUserInfo(packageName, pid, uid));
-            }
-        }
-
-        @Override
-        public void onNext(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchNext(createRemoteUserInfo(packageName, pid, uid));
-            }
-        }
-
-        @Override
-        public void onPrevious(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid));
-            }
-        }
-
-        @Override
-        public void onFastForward(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchFastForward(
-                        createRemoteUserInfo(packageName, pid, uid));
-            }
-        }
-
-        @Override
-        public void onRewind(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchRewind(createRemoteUserInfo(packageName, pid, uid));
-            }
-        }
-
-        @Override
-        public void onSeekTo(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, long pos) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchSeekTo(
-                        createRemoteUserInfo(packageName, pid, uid), pos);
-            }
-        }
-
-        @Override
-        public void onRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
-                Rating rating) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchRate(
-                        createRemoteUserInfo(packageName, pid, uid), rating);
-            }
-        }
-
-        @Override
-        public void onCustomAction(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String action, Bundle args) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchCustomAction(
-                        createRemoteUserInfo(packageName, pid, uid), action, args);
-            }
-        }
-
-        @Override
-        public void onAdjustVolume(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, int direction) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchAdjustVolume(
-                        createRemoteUserInfo(packageName, pid, uid), direction);
-            }
-        }
-
-        @Override
-        public void onSetVolumeTo(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, int value) {
-            MediaSessionEngine sessionImpl = mSessionImpl.get();
-            if (sessionImpl != null) {
-                sessionImpl.dispatchSetVolumeTo(
-                        createRemoteUserInfo(packageName, pid, uid), value);
-            }
-        }
-
-        void setSessionImpl(MediaSessionEngine sessionImpl) {
-            mSessionImpl = new WeakReference<>(sessionImpl);
-        }
-    }
-
-    /**
+     /**
      * A single item that is part of the play queue. It contains a description
      * of the item and its id in the queue.
      */
diff --git a/media/apex/java/android/media/session/MediaSessionProviderService.java b/media/java/android/media/session/MediaSessionProviderService.java
similarity index 100%
rename from media/apex/java/android/media/session/MediaSessionProviderService.java
rename to media/java/android/media/session/MediaSessionProviderService.java
diff --git a/media/apex/java/android/media/session/PlaybackState.aidl b/media/java/android/media/session/PlaybackState.aidl
similarity index 100%
rename from media/apex/java/android/media/session/PlaybackState.aidl
rename to media/java/android/media/session/PlaybackState.aidl
diff --git a/media/apex/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
similarity index 100%
rename from media/apex/java/android/media/session/PlaybackState.java
rename to media/java/android/media/session/PlaybackState.java
diff --git a/media/apex/java/android/media/session/SessionCallbackLink.aidl b/media/java/android/media/session/SessionCallbackLink.aidl
similarity index 100%
rename from media/apex/java/android/media/session/SessionCallbackLink.aidl
rename to media/java/android/media/session/SessionCallbackLink.aidl
diff --git a/media/apex/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java
similarity index 79%
rename from media/apex/java/android/media/session/SessionCallbackLink.java
rename to media/java/android/media/session/SessionCallbackLink.java
index 3bcb65c..4c2918a 100644
--- a/media/apex/java/android/media/session/SessionCallbackLink.java
+++ b/media/java/android/media/session/SessionCallbackLink.java
@@ -25,6 +25,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.media.Rating;
+import android.media.session.MediaSessionManager.RemoteUserInfo;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -35,6 +36,8 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 
+import java.lang.ref.WeakReference;
+
 /**
  * Handles incoming commands to {@link MediaSession.Callback}.
  * @hide
@@ -42,16 +45,15 @@
 @SystemApi
 public final class SessionCallbackLink implements Parcelable {
     final Context mContext;
-    final CallbackStub mCallbackStub;
     final ISessionCallback mISessionCallback;
 
     /**
      * Constructor for stub (Callee)
+     * @hide
      */
-    SessionCallbackLink(@NonNull Context context, @NonNull CallbackStub callbackStub) {
+    public SessionCallbackLink(@NonNull Context context) {
         mContext = context;
-        mCallbackStub = callbackStub;
-        mISessionCallback = new CallbackStubProxy();
+        mISessionCallback = new CallbackStub();
     }
 
     /**
@@ -59,11 +61,19 @@
      */
     public SessionCallbackLink(IBinder binder) {
         mContext = null;
-        mCallbackStub = null;
         mISessionCallback = ISessionCallback.Stub.asInterface(binder);
     }
 
     /**
+     * Set {@link MediaSessionEngine} which will be used by {@link CallbackStub}.
+     */
+    void setSessionEngine(@Nullable MediaSessionEngine sessionImpl) {
+        if (mISessionCallback instanceof CallbackStub) {
+            ((CallbackStub) mISessionCallback).mSessionImpl = new WeakReference<>(sessionImpl);
+        }
+    }
+
+    /**
      * Notify session that a controller sends a command.
      *
      * @param packageName the package name of the controller
@@ -540,139 +550,24 @@
                 }
             };
 
-    /**
-     * Class for Stub implementation
-     */
-    abstract static class CallbackStub {
-        /** Stub method for ISessionCallback.notifyCommand */
-        public void onCommand(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, @NonNull String command,
-                @Nullable Bundle args, @Nullable ResultReceiver cb) {
+    private class CallbackStub extends ISessionCallback.Stub {
+        private WeakReference<MediaSessionEngine> mSessionImpl;
+
+        private RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid) {
+            return new RemoteUserInfo(packageName, pid, uid);
         }
 
-        /** Stub method for ISessionCallback.notifyMediaButton */
-        public void onMediaButton(@NonNull String packageName, int pid, int uid,
-                @NonNull Intent mediaButtonIntent, int sequenceNumber,
-                @Nullable ResultReceiver cb) {
-        }
-
-        /** Stub method for ISessionCallback.notifyMediaButtonFromController */
-        public void onMediaButtonFromController(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrepare */
-        public void onPrepare(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrepareFromMediaId */
-        public void onPrepareFromMediaId(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
-                @Nullable Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrepareFromSearch */
-        public void onPrepareFromSearch(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrepareFromUri */
-        public void onPrepareFromUri(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPlay */
-        public void onPlay(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPlayFromMediaId */
-        public void onPlayFromMediaId(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
-                @Nullable Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPlayFromSearch */
-        public void onPlayFromSearch(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPlayFromUri */
-        public void onPlayFromUri(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifySkipToTrack */
-        public void onSkipToTrack(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, long id) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPause */
-        public void onPause(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyStop */
-        public void onStop(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyNext */
-        public void onNext(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrevious */
-        public void onPrevious(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyFastForward */
-        public void onFastForward(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyRewind */
-        public void onRewind(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifySeekTo */
-        public void onSeekTo(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, long pos) {
-        }
-
-        /** Stub method for ISessionCallback.notifyRate */
-        public void onRate(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, @NonNull Rating rating) {
-        }
-
-        /** Stub method for ISessionCallback.notifyCustomAction */
-        public void onCustomAction(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, @NonNull String action,
-                @Nullable Bundle args) {
-        }
-
-        /** Stub method for ISessionCallback.notifyAdjustVolume */
-        public void onAdjustVolume(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, int direction) {
-        }
-
-        /** Stub method for ISessionCallback.notifySetVolumeTo */
-        public void onSetVolumeTo(@NonNull String packageName, int pid, int uid,
-                @NonNull ControllerCallbackLink caller, int value) {
-        }
-    }
-
-    private class CallbackStubProxy extends ISessionCallback.Stub {
         @Override
         public void notifyCommand(String packageName, int pid, int uid,
                 ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onCommand(packageName, pid, uid, caller, command, args, cb);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchCommand(createRemoteUserInfo(packageName, pid, uid),
+                            command, args, cb);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -684,9 +579,15 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onMediaButton(packageName, pid, uid, mediaButtonIntent,
-                        sequenceNumber, cb);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchMediaButton(
+                            createRemoteUserInfo(packageName, pid, uid), mediaButtonIntent);
+                }
             } finally {
+                if (cb != null) {
+                    cb.send(sequenceNumber, null);
+                }
                 Binder.restoreCallingIdentity(token);
             }
         }
@@ -697,8 +598,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onMediaButtonFromController(packageName, pid, uid, caller,
-                        mediaButtonIntent);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid),
+                            mediaButtonIntent);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -710,7 +614,10 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPrepare(packageName, pid, uid, caller);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid));
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -722,7 +629,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPrepareFromMediaId(
+                            createRemoteUserInfo(packageName, pid, uid), mediaId, extras);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -734,7 +645,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPrepareFromSearch(
+                            createRemoteUserInfo(packageName, pid, uid), query, extras);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -746,7 +661,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPrepareFromUri(
+                            createRemoteUserInfo(packageName, pid, uid), uri, extras);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -758,7 +677,10 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPlay(packageName, pid, uid, caller);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPlay(createRemoteUserInfo(packageName, pid, uid));
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -770,7 +692,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPlayFromMediaId(
+                            createRemoteUserInfo(packageName, pid, uid), mediaId, extras);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -782,7 +708,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPlayFromSearch(
+                            createRemoteUserInfo(packageName, pid, uid), query, extras);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -794,7 +724,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPlayFromUri(
+                            createRemoteUserInfo(packageName, pid, uid), uri, extras);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -806,7 +740,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onSkipToTrack(packageName, pid, uid, caller, id);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchSkipToItem(
+                            createRemoteUserInfo(packageName, pid, uid), id);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -818,7 +756,10 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPause(packageName, pid, uid, caller);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPause(createRemoteUserInfo(packageName, pid, uid));
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -830,7 +771,10 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onStop(packageName, pid, uid, caller);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchStop(createRemoteUserInfo(packageName, pid, uid));
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -842,7 +786,10 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onNext(packageName, pid, uid, caller);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchNext(createRemoteUserInfo(packageName, pid, uid));
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -854,7 +801,10 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onPrevious(packageName, pid, uid, caller);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid));
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -866,7 +816,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onFastForward(packageName, pid, uid, caller);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchFastForward(
+                            createRemoteUserInfo(packageName, pid, uid));
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -878,7 +832,10 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onRewind(packageName, pid, uid, caller);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchRewind(createRemoteUserInfo(packageName, pid, uid));
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -890,7 +847,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onSeekTo(packageName, pid, uid, caller, pos);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchSeekTo(
+                            createRemoteUserInfo(packageName, pid, uid), pos);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -902,7 +863,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onRate(packageName, pid, uid, caller, rating);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchRate(
+                            createRemoteUserInfo(packageName, pid, uid), rating);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -913,7 +878,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onCustomAction(packageName, pid, uid, caller, action, args);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchCustomAction(
+                            createRemoteUserInfo(packageName, pid, uid), action, args);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -925,7 +894,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onAdjustVolume(packageName, pid, uid, caller, direction);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchAdjustVolume(
+                            createRemoteUserInfo(packageName, pid, uid), direction);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -937,7 +910,11 @@
             ensureMediaControlPermission();
             final long token = Binder.clearCallingIdentity();
             try {
-                mCallbackStub.onSetVolumeTo(packageName, pid, uid, caller, value);
+                MediaSessionEngine sessionImpl = mSessionImpl.get();
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchSetVolumeTo(
+                            createRemoteUserInfo(packageName, pid, uid), value);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/media/apex/java/android/media/session/SessionLink.aidl b/media/java/android/media/session/SessionLink.aidl
similarity index 100%
rename from media/apex/java/android/media/session/SessionLink.aidl
rename to media/java/android/media/session/SessionLink.aidl
diff --git a/media/apex/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java
similarity index 100%
rename from media/apex/java/android/media/session/SessionLink.java
rename to media/java/android/media/session/SessionLink.java
diff --git a/media/apex/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
similarity index 100%
rename from media/apex/java/android/service/media/IMediaBrowserService.aidl
rename to media/java/android/service/media/IMediaBrowserService.aidl
diff --git a/media/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
similarity index 100%
rename from media/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
rename to media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
diff --git a/media/apex/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
similarity index 100%
rename from media/apex/java/android/service/media/MediaBrowserService.java
rename to media/java/android/service/media/MediaBrowserService.java
diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml
index 777283d..be2cb0d8 100644
--- a/packages/CarSystemUI/res/values/integers_car.xml
+++ b/packages/CarSystemUI/res/values/integers_car.xml
@@ -23,7 +23,7 @@
     <!-- Number of milliseconds user can spend driving with the keyguard up. After that, we switch to Guest. -->
     <!-- If the number is negative, the feature is disabled.
          If it's zero, we switch to guest immediately as we start driving. -->
-    <integer name="driving_on_keyguard_timeout_ms">30000</integer>
+    <integer name="driving_on_keyguard_timeout_ms">-1</integer>
 
     <!--Percentage of the screen height, from the bottom, that a notification panel being
     partially closed at will result in it remaining open if released-->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 4453121..23e5f0e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -4231,7 +4231,7 @@
 
                         String defLocationMode = Integer.toString(
                                 !TextUtils.isEmpty(locationProvidersAllowed.getValue())
-                                        ? Secure.LOCATION_MODE_HIGH_ACCURACY
+                                        ? Secure.LOCATION_MODE_ON
                                         : Secure.LOCATION_MODE_OFF);
                         secureSettings.insertSettingLocked(
                                 Secure.LOCATION_MODE, defLocationMode,
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 7432f9c..41acf82 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -405,7 +405,7 @@
     <!-- Header for typographic clock face. [CHAR LIMIT=8] -->
     <string name="type_clock_header">It\u2019s</string>
 
-    <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=8] -->
+    <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=12] -->
     <string-array name="type_clock_hours">
         <item>Twelve</item>
         <item>One</item>
@@ -421,7 +421,7 @@
         <item>Eleven</item>
     </string-array>
 
-    <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=16] -->
+    <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=20] -->
     <string-array name="type_clock_minutes">
         <item>O\u2019Clock</item>
         <item>O\u2019One</item>
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index f4ac130..fc43882 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -348,8 +348,8 @@
     }
 
     int getRelevantEventTypes() {
-        return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK : 0)
-                | mEventTypes;
+        return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK
+                : AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) | mEventTypes;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 6bac93c..33c6dd2 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -2199,7 +2199,7 @@
             return false;
         }
 
-        if (mBackgroundThrottlePackageWhitelist.contains(record.mReceiver.mIdentity.mPackageName)) {
+        if (mIgnoreSettingsPackageWhitelist.contains(record.mReceiver.mIdentity.mPackageName)) {
             return true;
         }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index cecd55a3..f2329d3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1541,10 +1541,6 @@
         mCallbacks = new Callbacks(FgThread.get().getLooper());
         mLockPatternUtils = new LockPatternUtils(mContext);
 
-        mPmInternal = LocalServices.getService(PackageManagerInternal.class);
-        mUmInternal = LocalServices.getService(UserManagerInternal.class);
-        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
-
         HandlerThread hthread = new HandlerThread(TAG);
         hthread.start();
         mHandler = new StorageManagerServiceHandler(hthread.getLooper());
@@ -1662,6 +1658,19 @@
     }
 
     private void servicesReady() {
+        mPmInternal = LocalServices.getService(PackageManagerInternal.class);
+        mUmInternal = LocalServices.getService(UserManagerInternal.class);
+        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+
+        mIPackageManager = IPackageManager.Stub.asInterface(
+                ServiceManager.getService("package"));
+        mIAppOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
+        try {
+            mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback);
+        } catch (RemoteException e) {
+        }
+
         synchronized (mLock) {
             final boolean thisIsolatedStorage = StorageManager.hasIsolatedStorage();
             if (mLastIsolatedStorage == thisIsolatedStorage) {
@@ -1734,14 +1743,6 @@
                 .registerScreenObserver(this);
 
         mSystemReady = true;
-        mIPackageManager = IPackageManager.Stub.asInterface(
-                ServiceManager.getService("package"));
-        mIAppOpsService = IAppOpsService.Stub.asInterface(
-                ServiceManager.getService(Context.APP_OPS_SERVICE));
-        try {
-            mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback);
-        } catch (RemoteException e) {
-        }
         mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
     }
 
diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java
index 53e8ce4..f74a4385 100644
--- a/services/core/java/com/android/server/ThreadPriorityBooster.java
+++ b/services/core/java/com/android/server/ThreadPriorityBooster.java
@@ -43,9 +43,9 @@
 
     public void boost() {
         final int tid = myTid();
-        final int prevPriority = getThreadPriority(tid);
         final PriorityState state = mThreadState.get();
         if (state.regionCounter == 0) {
+            final int prevPriority = getThreadPriority(tid);
             state.prevPriority = prevPriority;
             if (prevPriority > mBoostToPriority) {
                 setThreadPriority(tid, mBoostToPriority);
@@ -60,9 +60,11 @@
     public void reset() {
         final PriorityState state = mThreadState.get();
         state.regionCounter--;
-        final int currentPriority = getThreadPriority(myTid());
-        if (state.regionCounter == 0 && state.prevPriority != currentPriority) {
-            setThreadPriority(myTid(), state.prevPriority);
+        if (state.regionCounter == 0) {
+            final int currentPriority = getThreadPriority(myTid());
+            if (state.prevPriority != currentPriority) {
+                setThreadPriority(myTid(), state.prevPriority);
+            }
         }
     }
 
@@ -77,9 +79,11 @@
         mBoostToPriority = priority;
         final PriorityState state = mThreadState.get();
         final int tid = myTid();
-        final int prevPriority = getThreadPriority(tid);
-        if (state.regionCounter != 0 && prevPriority != priority) {
-            setThreadPriority(tid, priority);
+        if (state.regionCounter != 0) {
+            final int prevPriority = getThreadPriority(tid);
+            if (prevPriority != priority) {
+                setThreadPriority(tid, priority);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index bb55ec31..1118014 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -19,6 +19,7 @@
 import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_STATSD_SAMPLE_RATE;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3;
@@ -45,6 +46,7 @@
 import java.io.FileOutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Random;
 
 public final class AppCompactor {
 
@@ -65,6 +67,8 @@
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000;
+    // The sampling rate to push app compaction events into statsd for upload.
+    @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f;
 
     @VisibleForTesting
     interface PropertyChangedCallbackForTest {
@@ -104,6 +108,8 @@
                                 || KEY_COMPACT_THROTTLE_3.equals(name)
                                 || KEY_COMPACT_THROTTLE_4.equals(name)) {
                             updateCompactionThrottles();
+                        } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) {
+                            updateStatsdSampleRate();
                         }
                     }
                     if (mTestCallback != null) {
@@ -116,21 +122,25 @@
 
     // Configured by phenotype. Updates from the server take effect immediately.
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting String mCompactActionSome =
+    @VisibleForTesting volatile String mCompactActionSome =
             compactActionIntToString(DEFAULT_COMPACT_ACTION_1);
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting String mCompactActionFull =
+    @VisibleForTesting volatile String mCompactActionFull =
             compactActionIntToString(DEFAULT_COMPACT_ACTION_2);
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
+    @VisibleForTesting volatile long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
+    @VisibleForTesting volatile long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
+    @VisibleForTesting volatile long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
+    @VisibleForTesting volatile long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
     @GuardedBy("mPhenotypeFlagLock")
-    private boolean mUseCompaction = DEFAULT_USE_COMPACTION;
+    private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
+
+    private final Random mRandom = new Random();
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting volatile float mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
 
     // Handler on which compaction runs.
     private Handler mCompactionHandler;
@@ -158,6 +168,7 @@
             updateUseCompaction();
             updateCompactionActions();
             updateCompactionThrottles();
+            updateStatsdSampleRate();
         }
     }
 
@@ -181,6 +192,7 @@
             pw.println("  " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull);
             pw.println("  " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome);
             pw.println("  " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull);
+            pw.println("  " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mStatsdSampleRate);
         }
     }
 
@@ -289,6 +301,19 @@
         }
     }
 
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateStatsdSampleRate() {
+        String sampleRateFlag = DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_STATSD_SAMPLE_RATE);
+        try {
+            mStatsdSampleRate = TextUtils.isEmpty(sampleRateFlag)
+                    ? DEFAULT_STATSD_SAMPLE_RATE : Float.parseFloat(sampleRateFlag);
+        } catch (NumberFormatException e) {
+            mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
+        }
+        mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate));
+    }
+
     @VisibleForTesting
     static String compactActionIntToString(int action) {
         switch(action) {
@@ -385,11 +410,16 @@
                                 rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
                                 rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
                                 lastCompactAction, lastCompactTime, msg.arg1, msg.arg2);
-                        StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction,
-                                rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
-                                rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
-                                lastCompactAction, lastCompactTime, msg.arg1,
-                                ActivityManager.processStateAmToProto(msg.arg2));
+                        // Note that as above not taking mPhenoTypeFlagLock here to avoid locking
+                        // on every single compaction for a flag that will seldom change and the
+                        // impact of reading the wrong value here is low.
+                        if (mRandom.nextFloat() < mStatsdSampleRate) {
+                            StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction,
+                                    rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
+                                    rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
+                                    lastCompactAction, lastCompactTime, msg.arg1,
+                                    ActivityManager.processStateAmToProto(msg.arg2));
+                        }
                         synchronized (mAm) {
                             proc.lastCompactTime = end;
                             proc.lastCompactAction = pendingAction;
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 5b469fe..2061b26 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -16,9 +16,9 @@
 
 package com.android.server.attention;
 
+import static android.provider.DeviceConfig.AttentionManagerService.COMPONENT_NAME;
 import static android.provider.DeviceConfig.AttentionManagerService.NAMESPACE;
-import static android.provider.DeviceConfig.AttentionManagerService.PROPERTY_COMPONENT_NAME;
-import static android.provider.DeviceConfig.AttentionManagerService.PROPERTY_SERVICE_ENABLED;
+import static android.provider.DeviceConfig.AttentionManagerService.SERVICE_ENABLED;
 
 import android.Manifest;
 import android.annotation.Nullable;
@@ -129,7 +129,7 @@
     }
 
     private boolean isServiceEnabled() {
-        final String enabled = DeviceConfig.getProperty(NAMESPACE, PROPERTY_SERVICE_ENABLED);
+        final String enabled = DeviceConfig.getProperty(NAMESPACE, SERVICE_ENABLED);
         return enabled == null ? DEFAULT_SERVICE_ENABLED : "true".equals(enabled);
     }
 
@@ -279,7 +279,7 @@
      * system.
      */
     private static ComponentName resolveAttentionService(Context context) {
-        final String flag = DeviceConfig.getProperty(NAMESPACE, PROPERTY_COMPONENT_NAME);
+        final String flag = DeviceConfig.getProperty(NAMESPACE, COMPONENT_NAME);
 
         final String componentNameString = flag != null ? flag : context.getString(
                 R.string.config_defaultAttentionService);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index d652f93..deaa931 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -600,7 +600,7 @@
                     break;
                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
                     mDeviceInventory.onSetA2dpSinkConnectionState(
-                            (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1, msg.arg2);
+                            (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
                     break;
                 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
                     mDeviceInventory.onSetA2dpSourceConnectionState(
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index eb76e6e0..97649a7 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -147,18 +147,20 @@
     }
 
     /*package*/ void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo,
-            @AudioService.BtProfileConnectionState int state, int a2dpVolume) {
+            @AudioService.BtProfileConnectionState int state) {
         final BluetoothDevice btDevice = btInfo.getBtDevice();
+        int a2dpVolume = btInfo.getVolume();
         if (AudioService.DEBUG_DEVICES) {
             Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state="
-                    + state + " is dock=" + btDevice.isBluetoothDock());
+                    + state + " is dock=" + btDevice.isBluetoothDock() + " vol=" + a2dpVolume);
         }
         String address = btDevice.getAddress();
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
         }
         AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
-                "A2DP sink connected: device addr=" + address + " state=" + state));
+                "A2DP sink connected: device addr=" + address + " state=" + state
+                        + " vol=" + a2dpVolume));
 
         final int a2dpCodec;
         synchronized (mDeviceBroker.mA2dpAvrcpLock) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index df33bf24..1723163 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -392,12 +392,14 @@
     * e.g. user on homescreen, no app playing anything, presses hardware volume buttons, this
     *    stream type is controlled.
     */
-   protected static final int DEFAULT_VOL_STREAM_NO_PLAYBACK = AudioSystem.STREAM_MUSIC;
+    protected static final int DEFAULT_VOL_STREAM_NO_PLAYBACK = AudioSystem.STREAM_MUSIC;
 
     private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
         public void onError(int error) {
             switch (error) {
             case AudioSystem.AUDIO_STATUS_SERVER_DIED:
+                mRecordMonitor.clear();
+
                 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
                         SENDMSG_NOOP, 0, 0, null, 0);
                 sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 9d6628c..b2c7ff3 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -78,24 +78,27 @@
                 updateSnapshot(event, uid, session, source, recordingInfo,
                 portId, silenced, activeSource, clientEffects, effects);
         if (configsSystem != null){
-            synchronized (mClients) {
-                // list of recording configurations for "public consumption". It is only computed if
-                // there are non-system recording activity listeners.
-                final List<AudioRecordingConfiguration> configsPublic = mHasPublicClients ?
-                        anonymizeForPublicConsumption(configsSystem) :
-                            new ArrayList<AudioRecordingConfiguration>();
-                final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
-                while (clientIterator.hasNext()) {
-                    final RecMonitorClient rmc = clientIterator.next();
-                    try {
-                        if (rmc.mIsPrivileged) {
-                            rmc.mDispatcherCb.dispatchRecordingConfigChange(configsSystem);
-                        } else {
-                            rmc.mDispatcherCb.dispatchRecordingConfigChange(configsPublic);
-                        }
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e);
+            dispatchCallbacks(configsSystem);
+        }
+    }
+    private void dispatchCallbacks(List<AudioRecordingConfiguration> configs) {
+        synchronized (mClients) {
+            // list of recording configurations for "public consumption". It is only computed if
+            // there are non-system recording activity listeners.
+            final List<AudioRecordingConfiguration> configsPublic = mHasPublicClients
+                    ? anonymizeForPublicConsumption(configs) :
+                      new ArrayList<AudioRecordingConfiguration>();
+            final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+            while (clientIterator.hasNext()) {
+                final RecMonitorClient rmc = clientIterator.next();
+                try {
+                    if (rmc.mIsPrivileged) {
+                        rmc.mDispatcherCb.dispatchRecordingConfigChange(configs);
+                    } else {
+                        rmc.mDispatcherCb.dispatchRecordingConfigChange(configsPublic);
                     }
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e);
                 }
             }
         }
@@ -130,6 +133,13 @@
         AudioSystem.setRecordingCallback(this);
     }
 
+    void clear() {
+        synchronized (mRecordConfigs) {
+            mRecordConfigs.clear();
+        }
+        dispatchCallbacks(new ArrayList<AudioRecordingConfiguration>());
+    }
+
     void registerRecordingCallback(IRecordingConfigDispatcher rcdb, boolean isPrivileged) {
         if (rcdb == null) {
             return;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index db3928e..2a8462b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -592,6 +592,9 @@
     }
 
     public BrightnessConfiguration getDefaultBrightnessConfiguration() {
+        if (mAutomaticBrightnessController == null) {
+            return null;
+        }
         return mAutomaticBrightnessController.getDefaultConfig();
     }
 
diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java
index 3ebba00..6f2bfc3 100644
--- a/services/core/java/com/android/server/incident/IncidentCompanionService.java
+++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java
@@ -16,38 +16,18 @@
 
 package com.android.server.incident;
 
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
-import android.net.Uri;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IIncidentAuthListener;
 import android.os.IIncidentCompanion;
-import android.os.IncidentManager;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
 
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
-// TODO: User changes should deny everything that's pending.
-
 /**
  * Helper service for incidentd and dumpstated to provide user feedback
  * and authorization for bug and inicdent reports to be taken.
@@ -55,83 +35,26 @@
 public class IncidentCompanionService extends SystemService {
     static final String TAG = "IncidentCompanionService";
 
-    private final Handler mHandler = new Handler();
-    private final RequestQueue mRequestQueue = new RequestQueue(mHandler);
-    private final PackageManager mPackageManager;
-    private final AppOpsManager mAppOpsManager;
-
-    //
-    // All fields below must be protected by mLock
-    //
-    private final Object mLock = new Object();
-    private final ArrayList<PendingReportRec> mPending = new ArrayList();
-
     /**
-     * The next ID we'll use when we make a PendingReportRec.
+     * Tracker for reports pending approval.
      */
-    private int mNextPendingId = 1;
-
-    /**
-     * One for each authorization that's pending.
-     */
-    private final class PendingReportRec {
-        public int id;
-        public String callingPackage;
-        public int flags;
-        public IIncidentAuthListener listener;
-        public long addedRealtime;
-        public long addedWalltime;
-
-        /**
-         * Construct a PendingReportRec, with an auto-incremented id.
-         */
-        PendingReportRec(String callingPackage, int flags, IIncidentAuthListener listener) {
-            this.id = mNextPendingId++;
-            this.callingPackage = callingPackage;
-            this.flags = flags;
-            this.listener = listener;
-            this.addedRealtime = SystemClock.elapsedRealtime();
-            this.addedWalltime = System.currentTimeMillis();
-        }
-
-        /**
-         * Get the Uri that contains the flattened data.
-         */
-        Uri getUri() {
-            return (new Uri.Builder())
-                    .scheme(IncidentManager.URI_SCHEME)
-                    .authority(IncidentManager.URI_AUTHORITY)
-                    .path(IncidentManager.URI_PATH)
-                    .appendQueryParameter(IncidentManager.URI_PARAM_ID, Integer.toString(id))
-                    .appendQueryParameter(IncidentManager.URI_PARAM_CALLING_PACKAGE, callingPackage)
-                    .appendQueryParameter(IncidentManager.URI_PARAM_FLAGS, Integer.toString(flags))
-                    .appendQueryParameter(IncidentManager.URI_PARAM_TIMESTAMP,
-                            Long.toString(addedWalltime))
-                    .build();
-        }
-    }
+    private PendingReports mPendingReports;
 
     /**
      * Implementation of the IIncidentCompanion binder interface.
      */
     private final class BinderService extends IIncidentCompanion.Stub {
         /**
-         * ONEWAY binder call to initiate authorizing the report.  The actual logic is posted
-         * to mRequestQueue, and may happen later.  The security checks need to happen here.
+         * ONEWAY binder call to initiate authorizing the report.
          */
         @Override
-        public void authorizeReport(int callingUid, final String callingPackage, final int flags,
+        public void authorizeReport(int callingUid, final String callingPackage, int flags,
                 final IIncidentAuthListener listener) {
             enforceRequestAuthorizationPermission();
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                // Starting the system server is complicated, and rather than try to
-                // have a complicated lifecycle that we share with dumpstated and incidentd,
-                // we will accept the request, and then display it whenever it becomes possible to.
-                mRequestQueue.enqueue(listener.asBinder(), true, () -> {
-                    authorizeReportImpl(callingUid, callingPackage, flags, listener);
-                });
+                mPendingReports.authorizeReport(callingUid, callingPackage, flags, listener);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -152,9 +75,7 @@
             // authorize/cancel pairs.
             final long ident = Binder.clearCallingIdentity();
             try {
-                mRequestQueue.enqueue(listener.asBinder(), false, () -> {
-                    cancelReportImpl(listener);
-                });
+                mPendingReports.cancelAuthorization(listener);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -167,19 +88,11 @@
         @Override
         public List<String> getPendingReports() {
             enforceAuthorizePermission();
-
-            synchronized (mLock) {
-                final int size = mPending.size();
-                final ArrayList<String> result = new ArrayList(size);
-                for (int i = 0; i < size; i++) {
-                    result.add(mPending.get(i).getUri().toString());
-                }
-                return result;
-            }
+            return mPendingReports.getPendingReports();
         }
 
         /**
-         * ONEWAY binder call to mark a report as approved.
+         * SYNCHRONOUS binder call to mark a report as approved.
          */
         @Override
         public void approveReport(String uri) {
@@ -187,32 +100,14 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                final PendingReportRec rec;
-                synchronized (mLock) {
-                    rec = findAndRemovePendingReportRecLocked(uri);
-                    if (rec == null) {
-                        Log.e(TAG, "confirmApproved: Couldn't find record for uri: " + uri);
-                        return;
-                    }
-                }
-
-                // Re-do the broadcast, so whoever is listening knows the list changed,
-                // in case another one was added in the meantime.
-                sendBroadcast();
-
-                Log.i(TAG, "Approved report: " + uri);
-                try {
-                    rec.listener.onReportApproved();
-                } catch (RemoteException ex) {
-                    Log.w(TAG, "Failed calling back for approval for: " + uri, ex);
-                }
+                mPendingReports.approveReport(uri);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         }
 
         /**
-         * ONEWAY binder call to mark a report as NOT approved.
+         * SYNCHRONOUS binder call to mark a report as NOT approved.
          */
         @Override
         public void denyReport(String uri) {
@@ -220,25 +115,7 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                final PendingReportRec rec;
-                synchronized (mLock) {
-                    rec = findAndRemovePendingReportRecLocked(uri);
-                    if (rec == null) {
-                        Log.e(TAG, "confirmDenied: Couldn't find record for uri: " + uri);
-                        return;
-                    }
-                }
-
-                // Re-do the broadcast, so whoever is listening knows the list changed,
-                // in case another one was added in the meantime.
-                sendBroadcast();
-
-                Log.i(TAG, "Denied report: " + uri);
-                try {
-                    rec.listener.onReportDenied();
-                } catch (RemoteException ex) {
-                    Log.w(TAG, "Failed calling back for denial for: " + uri, ex);
-                }
+                mPendingReports.denyReport(uri);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -252,27 +129,22 @@
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) {
                 return;
             }
-            if (args.length == 0) {
-                // Standard text dumpsys
-                final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-                synchronized (mLock) {
-                    final int size = mPending.size();
-                    writer.println("mPending: (" + size + ")");
-                    for (int i = 0; i < size; i++) {
-                        final PendingReportRec entry = mPending.get(i);
-                        writer.println(String.format("  %11d %s: %s", entry.addedRealtime,
-                                    df.format(new Date(entry.addedWalltime)),
-                                    entry.getUri().toString()));
-                    }
-                }
-            }
+            mPendingReports.dump(fd, writer, args);
         }
 
+        /**
+         * Inside the binder interface class because we want to do all of the authorization
+         * here, before calling out to the helper objects.
+         */
         private void enforceRequestAuthorizationPermission() {
             getContext().enforceCallingOrSelfPermission(
                     android.Manifest.permission.REQUEST_INCIDENT_REPORT_APPROVAL, null);
         }
 
+        /**
+         * Inside the binder interface class because we want to do all of the authorization
+         * here, before calling out to the helper objects.
+         */
         private void enforceAuthorizePermission() {
             getContext().enforceCallingOrSelfPermission(
                     android.Manifest.permission.APPROVE_INCIDENT_REPORTS, null);
@@ -285,8 +157,7 @@
      */
     public IncidentCompanionService(Context context) {
         super(context);
-        mPackageManager = context.getPackageManager();
-        mAppOpsManager = context.getSystemService(AppOpsManager.class);
+        mPendingReports = new PendingReports(context);
     }
 
     /**
@@ -307,239 +178,9 @@
         super.onBootPhase(phase);
         switch (phase) {
             case SystemService.PHASE_BOOT_COMPLETED:
-                // Release the enqueued work.
-                mRequestQueue.start();
+                mPendingReports.onBootCompleted();
                 break;
         }
     }
-
-    /**
-     * Start the confirmation process.
-     */
-    private void authorizeReportImpl(int callingUid, final String callingPackage, int flags,
-            final IIncidentAuthListener listener) {
-        // Enforce that the calling package pertains to the callingUid.
-        if (!isPackageInUid(callingUid, callingPackage)) {
-            Log.w(TAG, "Calling uid " + callingUid + " doesn't match package "
-                    + callingPackage);
-            denyReportBeforeAddingRec(listener, callingPackage);
-            return;
-        }
-
-        // Find the primary user of this device.
-        final int primaryUser = getAndValidateUser();
-        if (primaryUser == UserHandle.USER_NULL) {
-            denyReportBeforeAddingRec(listener, callingPackage);
-            return;
-        }
-
-        // Find the approver app (hint: it's PermissionController).
-        final ComponentName receiver = getApproverComponent(primaryUser);
-        if (receiver == null) {
-            // We couldn't find an approver... so deny the request here and now, before we
-            // do anything else.
-            denyReportBeforeAddingRec(listener, callingPackage);
-            return;
-        }
-
-        // Save the record for when the PermissionController comes back to authorize it.
-        PendingReportRec rec = null;
-        synchronized (mLock) {
-            rec = new PendingReportRec(callingPackage, flags, listener);
-            mPending.add(rec);
-        }
-
-        try {
-            listener.asBinder().linkToDeath(() -> {
-                Log.i(TAG, "Got death notification listener=" + listener);
-                cancelReportImpl(listener, receiver, primaryUser);
-            }, 0);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Remote died while trying to register death listener: " + rec.getUri());
-            // First, remove from our list.
-            cancelReportImpl(listener, receiver, primaryUser);
-        }
-
-        // Go tell Permission controller to start asking the user.
-        sendBroadcast(receiver, primaryUser);
-    }
-
-    /**
-     * Cancel a pending report request (because of an explicit call to cancel)
-     */
-    private void cancelReportImpl(IIncidentAuthListener listener) {
-        final int primaryUser = getAndValidateUser();
-        final ComponentName receiver = getApproverComponent(primaryUser);
-        if (primaryUser != UserHandle.USER_NULL && receiver != null) {
-            cancelReportImpl(listener, receiver, primaryUser);
-        }
-    }
-
-    /**
-     * Cancel a pending report request (either because of an explicit call to cancel
-     * by the calling app, or because of a binder death).
-     */
-    private void cancelReportImpl(IIncidentAuthListener listener, ComponentName receiver,
-            int primaryUser) {
-        // First, remove from our list.
-        synchronized (mLock) {
-            removePendingReportRecLocked(listener);
-        }
-        // Second, call back to PermissionController to say it's canceled.
-        sendBroadcast(receiver, primaryUser);
-    }
-
-    /**
-     * Send an extra copy of the broadcast, to tell them that the list has changed
-     * because of an addition or removal.  This function is less aggressive than
-     * authorizeReportImpl in logging about failures, because this is for use in
-     * cleanup cases to keep the apps' list in sync with ours.
-     */
-    private void sendBroadcast() {
-        final int primaryUser = getAndValidateUser();
-        if (primaryUser == UserHandle.USER_NULL) {
-            return;
-        }
-        final ComponentName receiver = getApproverComponent(primaryUser);
-        if (receiver == null) {
-            return;
-        }
-        sendBroadcast(receiver, primaryUser);
-    }
-
-    /**
-     * Send the confirmation broadcast.
-     */
-    private void sendBroadcast(ComponentName receiver, int primaryUser) {
-        final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED);
-        intent.setComponent(receiver);
-
-        // Send it to the primary user.
-        getContext().sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(primaryUser),
-                android.Manifest.permission.APPROVE_INCIDENT_REPORTS);
-    }
-
-    /**
-     * Remove a PendingReportRec keyed by uri, and return it.
-     */
-    private PendingReportRec findAndRemovePendingReportRecLocked(String uriString) {
-        final Uri uri = Uri.parse(uriString);
-        final int id;
-        try {
-            final String idStr = uri.getQueryParameter(IncidentManager.URI_PARAM_ID);
-            id = Integer.parseInt(idStr);
-        } catch (NumberFormatException ex) {
-            Log.w(TAG, "Can't parse id from: " + uriString);
-            return null;
-        }
-        final int size = mPending.size();
-        for (int i = 0; i < size; i++) {
-            final PendingReportRec rec = mPending.get(i);
-            if (rec.id == id) {
-                mPending.remove(i);
-                return rec;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Remove a PendingReportRec keyed by listener.
-     */
-    private void removePendingReportRecLocked(IIncidentAuthListener listener) {
-        final int size = mPending.size();
-        for (int i = 0; i < size; i++) {
-            final PendingReportRec rec = mPending.get(i);
-            if (rec.listener.asBinder() == listener.asBinder()) {
-                Log.i(TAG, "  ...Removed PendingReportRec index=" + i + ": " + rec.getUri());
-                mPending.remove(i);
-            }
-        }
-    }
-
-    /**
-     * Just call listener.deny() (wrapping the RemoteException), without try to
-     * add it to the list.
-     */
-    private void denyReportBeforeAddingRec(IIncidentAuthListener listener, String pkg) {
-        try {
-            listener.onReportDenied();
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Failed calling back for denial for " + pkg, ex);
-        }
-    }
-
-    /**
-     * Check whether the current user is the primary user, and return the user id if they are.
-     * Returns UserHandle.USER_NULL if not valid.
-     */
-    private int getAndValidateUser() {
-        // Current user
-        UserInfo currentUser;
-        try {
-            currentUser = ActivityManager.getService().getCurrentUser();
-        } catch (RemoteException ex) {
-            // We're already inside the system process.
-            throw new RuntimeException(ex);
-        }
-
-        // Primary user
-        final UserManager um = UserManager.get(getContext());
-        final UserInfo primaryUser = um.getPrimaryUser();
-
-        // Check that we're using the right user.
-        if (currentUser == null) {
-            Log.w(TAG, "No current user.  Nobody to approve the report."
-                    + " The report will be denied.");
-            return UserHandle.USER_NULL;
-        }
-        if (primaryUser == null) {
-            Log.w(TAG, "No primary user.  Nobody to approve the report."
-                    + " The report will be denied.");
-            return UserHandle.USER_NULL;
-        }
-        if (primaryUser.id != currentUser.id) {
-            Log.w(TAG, "Only the primary user can approve bugreports, but they are not"
-                    + " the current user. The report will be denied.");
-            return UserHandle.USER_NULL;
-        }
-
-        return primaryUser.id;
-    }
-
-    /**
-     * Return the ComponentName of the BroadcastReceiver that will approve reports.
-     * The system must have zero or one of these installed.  We only look on the
-     * system partition.  When the broadcast happens, the component will also need
-     * have the APPROVE_INCIDENT_REPORTS permission.
-     */
-    private ComponentName getApproverComponent(int userId) {
-        // Find the one true BroadcastReceiver
-        final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED);
-        final List<ResolveInfo> matches = mPackageManager.queryBroadcastReceiversAsUser(intent,
-                PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
-        if (matches.size() == 1) {
-            return matches.get(0).getComponentInfo().getComponentName();
-        } else {
-            Log.w(TAG, "Didn't find exactly one BroadcastReceiver to handle "
-                    + Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED
-                    + ". The report will be denied. size="
-                    + matches.size() + ": matches=" + matches);
-            return null;
-        }
-    }
-
-    /**
-     * Return whether the package is one of the packages installed for the uid.
-     */
-    private boolean isPackageInUid(int uid, String packageName) {
-        try {
-            mAppOpsManager.checkPackage(uid, packageName);
-            return true;
-        } catch (SecurityException ex) {
-            return false;
-        }
-    }
 }
 
diff --git a/services/core/java/com/android/server/incident/PendingReports.java b/services/core/java/com/android/server/incident/PendingReports.java
new file mode 100644
index 0000000..519ed41
--- /dev/null
+++ b/services/core/java/com/android/server/incident/PendingReports.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.incident;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IIncidentAuthListener;
+import android.os.IncidentManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+// TODO: User changes should deny everything that's pending.
+
+/**
+ * Tracker for reports pending approval.
+ */
+class PendingReports {
+    static final String TAG = IncidentCompanionService.TAG;
+
+    private final Handler mHandler = new Handler();
+    private final RequestQueue mRequestQueue = new RequestQueue(mHandler);
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+    private final AppOpsManager mAppOpsManager;
+
+    //
+    // All fields below must be protected by mLock
+    //
+    private final Object mLock = new Object();
+    private final ArrayList<PendingReportRec> mPending = new ArrayList();
+
+    /**
+     * The next ID we'll use when we make a PendingReportRec.
+     */
+    private int mNextPendingId = 1;
+
+    /**
+     * One for each authorization that's pending.
+     */
+    private final class PendingReportRec {
+        public int id;
+        public String callingPackage;
+        public int flags;
+        public IIncidentAuthListener listener;
+        public long addedRealtime;
+        public long addedWalltime;
+
+        /**
+         * Construct a PendingReportRec, with an auto-incremented id.
+         */
+        PendingReportRec(String callingPackage, int flags, IIncidentAuthListener listener) {
+            this.id = mNextPendingId++;
+            this.callingPackage = callingPackage;
+            this.flags = flags;
+            this.listener = listener;
+            this.addedRealtime = SystemClock.elapsedRealtime();
+            this.addedWalltime = System.currentTimeMillis();
+        }
+
+        /**
+         * Get the Uri that contains the flattened data.
+         */
+        Uri getUri() {
+            return (new Uri.Builder())
+                    .scheme(IncidentManager.URI_SCHEME)
+                    .authority(IncidentManager.URI_AUTHORITY)
+                    .path(IncidentManager.URI_PATH)
+                    .appendQueryParameter(IncidentManager.URI_PARAM_ID, Integer.toString(id))
+                    .appendQueryParameter(IncidentManager.URI_PARAM_CALLING_PACKAGE, callingPackage)
+                    .appendQueryParameter(IncidentManager.URI_PARAM_FLAGS, Integer.toString(flags))
+                    .appendQueryParameter(IncidentManager.URI_PARAM_TIMESTAMP,
+                            Long.toString(addedWalltime))
+                    .build();
+        }
+    }
+
+    /**
+     * Construct new PendingReports with the context.
+     */
+    PendingReports(Context context) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
+    }
+
+    /**
+     * ONEWAY binder call to initiate authorizing the report.  The actual logic is posted
+     * to mRequestQueue, and may happen later.
+     * <p>
+     * The security checks are handled by IncidentCompanionService.
+     */
+    public void authorizeReport(int callingUid, final String callingPackage, final int flags,
+            final IIncidentAuthListener listener) {
+        // Starting the system server is complicated, and rather than try to
+        // have a complicated lifecycle that we share with dumpstated and incidentd,
+        // we will accept the request, and then display it whenever it becomes possible to.
+        mRequestQueue.enqueue(listener.asBinder(), true, () -> {
+            authorizeReportImpl(callingUid, callingPackage, flags, listener);
+        });
+    }
+
+    /**
+     * ONEWAY binder call to cancel the inbound authorization request.
+     * <p>
+     * This is a oneway call, and so is authorizeReport, so the
+     * caller's ordering is preserved.  The other calls on this object are synchronous, so
+     * their ordering is not guaranteed with respect to these calls.  So the implementation
+     * sends out extra broadcasts to allow for eventual consistency.
+     * <p>
+     * The security checks are handled by IncidentCompanionService.
+     */
+    public void cancelAuthorization(final IIncidentAuthListener listener) {
+        mRequestQueue.enqueue(listener.asBinder(), false, () -> {
+            cancelReportImpl(listener);
+        });
+    }
+
+    /**
+     * SYNCHRONOUS binder call to get the list of reports that are pending confirmation
+     * by the user.
+     * <p>
+     * The security checks are handled by IncidentCompanionService.
+     */
+    public List<String> getPendingReports() {
+        synchronized (mLock) {
+            final int size = mPending.size();
+            final ArrayList<String> result = new ArrayList(size);
+            for (int i = 0; i < size; i++) {
+                result.add(mPending.get(i).getUri().toString());
+            }
+            return result;
+        }
+    }
+
+    /**
+     * SYNCHRONOUS binder call to mark a report as approved.
+     * <p>
+     * The security checks are handled by IncidentCompanionService.
+     */
+    public void approveReport(String uri) {
+        final PendingReportRec rec;
+        synchronized (mLock) {
+            rec = findAndRemovePendingReportRecLocked(uri);
+            if (rec == null) {
+                Log.e(TAG, "confirmApproved: Couldn't find record for uri: " + uri);
+                return;
+            }
+        }
+
+        // Re-do the broadcast, so whoever is listening knows the list changed,
+        // in case another one was added in the meantime.
+        sendBroadcast();
+
+        Log.i(TAG, "Approved report: " + uri);
+        try {
+            rec.listener.onReportApproved();
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed calling back for approval for: " + uri, ex);
+        }
+    }
+
+    /**
+     * SYNCHRONOUS binder call to mark a report as NOT approved.
+     */
+    public void denyReport(String uri) {
+        final PendingReportRec rec;
+        synchronized (mLock) {
+            rec = findAndRemovePendingReportRecLocked(uri);
+            if (rec == null) {
+                Log.e(TAG, "confirmDenied: Couldn't find record for uri: " + uri);
+                return;
+            }
+        }
+
+        // Re-do the broadcast, so whoever is listening knows the list changed,
+        // in case another one was added in the meantime.
+        sendBroadcast();
+
+        Log.i(TAG, "Denied report: " + uri);
+        try {
+            rec.listener.onReportDenied();
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed calling back for denial for: " + uri, ex);
+        }
+    }
+
+    /**
+     * Implementation of adb shell dumpsys debugreportcompanion.
+     */
+    protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
+        if (args.length == 0) {
+            // Standard text dumpsys
+            final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+            synchronized (mLock) {
+                final int size = mPending.size();
+                writer.println("mPending: (" + size + ")");
+                for (int i = 0; i < size; i++) {
+                    final PendingReportRec entry = mPending.get(i);
+                    writer.println(String.format("  %11d %s: %s", entry.addedRealtime,
+                                df.format(new Date(entry.addedWalltime)),
+                                entry.getUri().toString()));
+                }
+            }
+        }
+    }
+
+    /**
+     * Handle the boot process... Starts everything running once the system is
+     * up enough for us to do UI.
+     */
+    public void onBootCompleted() {
+        // Release the enqueued work.
+        mRequestQueue.start();
+    }
+
+    /**
+     * Start the confirmation process.
+     */
+    private void authorizeReportImpl(int callingUid, final String callingPackage, int flags,
+            final IIncidentAuthListener listener) {
+        // Enforce that the calling package pertains to the callingUid.
+        if (!isPackageInUid(callingUid, callingPackage)) {
+            Log.w(TAG, "Calling uid " + callingUid + " doesn't match package "
+                    + callingPackage);
+            denyReportBeforeAddingRec(listener, callingPackage);
+            return;
+        }
+
+        // Find the primary user of this device.
+        final int primaryUser = getAndValidateUser();
+        if (primaryUser == UserHandle.USER_NULL) {
+            denyReportBeforeAddingRec(listener, callingPackage);
+            return;
+        }
+
+        // Find the approver app (hint: it's PermissionController).
+        final ComponentName receiver = getApproverComponent(primaryUser);
+        if (receiver == null) {
+            // We couldn't find an approver... so deny the request here and now, before we
+            // do anything else.
+            denyReportBeforeAddingRec(listener, callingPackage);
+            return;
+        }
+
+        // Save the record for when the PermissionController comes back to authorize it.
+        PendingReportRec rec = null;
+        synchronized (mLock) {
+            rec = new PendingReportRec(callingPackage, flags, listener);
+            mPending.add(rec);
+        }
+
+        try {
+            listener.asBinder().linkToDeath(() -> {
+                Log.i(TAG, "Got death notification listener=" + listener);
+                cancelReportImpl(listener, receiver, primaryUser);
+            }, 0);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Remote died while trying to register death listener: " + rec.getUri());
+            // First, remove from our list.
+            cancelReportImpl(listener, receiver, primaryUser);
+        }
+
+        // Go tell Permission controller to start asking the user.
+        sendBroadcast(receiver, primaryUser);
+    }
+
+    /**
+     * Cancel a pending report request (because of an explicit call to cancel)
+     */
+    private void cancelReportImpl(IIncidentAuthListener listener) {
+        final int primaryUser = getAndValidateUser();
+        final ComponentName receiver = getApproverComponent(primaryUser);
+        if (primaryUser != UserHandle.USER_NULL && receiver != null) {
+            cancelReportImpl(listener, receiver, primaryUser);
+        }
+    }
+
+    /**
+     * Cancel a pending report request (either because of an explicit call to cancel
+     * by the calling app, or because of a binder death).
+     */
+    private void cancelReportImpl(IIncidentAuthListener listener, ComponentName receiver,
+            int primaryUser) {
+        // First, remove from our list.
+        synchronized (mLock) {
+            removePendingReportRecLocked(listener);
+        }
+        // Second, call back to PermissionController to say it's canceled.
+        sendBroadcast(receiver, primaryUser);
+    }
+
+    /**
+     * Send an extra copy of the broadcast, to tell them that the list has changed
+     * because of an addition or removal.  This function is less aggressive than
+     * authorizeReportImpl in logging about failures, because this is for use in
+     * cleanup cases to keep the apps' list in sync with ours.
+     */
+    private void sendBroadcast() {
+        final int primaryUser = getAndValidateUser();
+        if (primaryUser == UserHandle.USER_NULL) {
+            return;
+        }
+        final ComponentName receiver = getApproverComponent(primaryUser);
+        if (receiver == null) {
+            return;
+        }
+        sendBroadcast(receiver, primaryUser);
+    }
+
+    /**
+     * Send the confirmation broadcast.
+     */
+    private void sendBroadcast(ComponentName receiver, int primaryUser) {
+        final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED);
+        intent.setComponent(receiver);
+
+        // Send it to the primary user.
+        mContext.sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(primaryUser),
+                android.Manifest.permission.APPROVE_INCIDENT_REPORTS);
+    }
+
+    /**
+     * Remove a PendingReportRec keyed by uri, and return it.
+     */
+    private PendingReportRec findAndRemovePendingReportRecLocked(String uriString) {
+        final Uri uri = Uri.parse(uriString);
+        final int id;
+        try {
+            final String idStr = uri.getQueryParameter(IncidentManager.URI_PARAM_ID);
+            id = Integer.parseInt(idStr);
+        } catch (NumberFormatException ex) {
+            Log.w(TAG, "Can't parse id from: " + uriString);
+            return null;
+        }
+        final int size = mPending.size();
+        for (int i = 0; i < size; i++) {
+            final PendingReportRec rec = mPending.get(i);
+            if (rec.id == id) {
+                mPending.remove(i);
+                return rec;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Remove a PendingReportRec keyed by listener.
+     */
+    private void removePendingReportRecLocked(IIncidentAuthListener listener) {
+        final int size = mPending.size();
+        for (int i = 0; i < size; i++) {
+            final PendingReportRec rec = mPending.get(i);
+            if (rec.listener.asBinder() == listener.asBinder()) {
+                Log.i(TAG, "  ...Removed PendingReportRec index=" + i + ": " + rec.getUri());
+                mPending.remove(i);
+            }
+        }
+    }
+
+    /**
+     * Just call listener.deny() (wrapping the RemoteException), without try to
+     * add it to the list.
+     */
+    private void denyReportBeforeAddingRec(IIncidentAuthListener listener, String pkg) {
+        try {
+            listener.onReportDenied();
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed calling back for denial for " + pkg, ex);
+        }
+    }
+
+    /**
+     * Check whether the current user is the primary user, and return the user id if they are.
+     * Returns UserHandle.USER_NULL if not valid.
+     */
+    private int getAndValidateUser() {
+        // Current user
+        UserInfo currentUser;
+        try {
+            currentUser = ActivityManager.getService().getCurrentUser();
+        } catch (RemoteException ex) {
+            // We're already inside the system process.
+            throw new RuntimeException(ex);
+        }
+
+        // Primary user
+        final UserManager um = UserManager.get(mContext);
+        final UserInfo primaryUser = um.getPrimaryUser();
+
+        // Check that we're using the right user.
+        if (currentUser == null) {
+            Log.w(TAG, "No current user.  Nobody to approve the report."
+                    + " The report will be denied.");
+            return UserHandle.USER_NULL;
+        }
+        if (primaryUser == null) {
+            Log.w(TAG, "No primary user.  Nobody to approve the report."
+                    + " The report will be denied.");
+            return UserHandle.USER_NULL;
+        }
+        if (primaryUser.id != currentUser.id) {
+            Log.w(TAG, "Only the primary user can approve bugreports, but they are not"
+                    + " the current user. The report will be denied.");
+            return UserHandle.USER_NULL;
+        }
+
+        return primaryUser.id;
+    }
+
+    /**
+     * Return the ComponentName of the BroadcastReceiver that will approve reports.
+     * The system must have zero or one of these installed.  We only look on the
+     * system partition.  When the broadcast happens, the component will also need
+     * have the APPROVE_INCIDENT_REPORTS permission.
+     */
+    private ComponentName getApproverComponent(int userId) {
+        // Find the one true BroadcastReceiver
+        final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED);
+        final List<ResolveInfo> matches = mPackageManager.queryBroadcastReceiversAsUser(intent,
+                PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+        if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().getComponentName();
+        } else {
+            Log.w(TAG, "Didn't find exactly one BroadcastReceiver to handle "
+                    + Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED
+                    + ". The report will be denied. size="
+                    + matches.size() + ": matches=" + matches);
+            return null;
+        }
+    }
+
+    /**
+     * Return whether the package is one of the packages installed for the uid.
+     */
+    private boolean isPackageInUid(int uid, String packageName) {
+        try {
+            mAppOpsManager.checkPackage(uid, packageName);
+            return true;
+        } catch (SecurityException ex) {
+            return false;
+        }
+    }
+}
+
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index e3c41f3..62c4815 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -34,9 +34,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
+import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
@@ -56,6 +58,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
@@ -153,6 +156,8 @@
 
         private final Object mVouchedSignaturesLocked = new Object();
 
+        private PackageInstallerService mPackageInstallerService;
+
         public LauncherAppsImpl(Context context) {
             mContext = context;
             mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
@@ -204,8 +209,7 @@
         }
 
         /*
-         * @see android.content.pm.ILauncherApps#addOnAppsChangedListener(
-         *          android.content.pm.IOnAppsChangedListener)
+         * @see android.content.pm.ILauncherApps#addOnAppsChangedListener
          */
         @Override
         public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener)
@@ -228,8 +232,7 @@
         }
 
         /*
-         * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener(
-         *          android.content.pm.IOnAppsChangedListener)
+         * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener
          */
         @Override
         public void removeOnAppsChangedListener(IOnAppsChangedListener listener)
@@ -246,6 +249,44 @@
         }
 
         /**
+         * @see android.content.pm.ILauncherApps#registerPackageInstallerCallback
+         */
+        @Override
+        public void registerPackageInstallerCallback(String callingPackage,
+                IPackageInstallerCallback callback) {
+            verifyCallingPackage(callingPackage);
+            UserHandle callingIdUserHandle = new UserHandle(getCallingUserId());
+            getPackageInstallerService().registerCallback(callback, eventUserId ->
+                            isEnabledProfileOf(callingIdUserHandle,
+                                    new UserHandle(eventUserId), "shouldReceiveEvent"));
+        }
+
+        @Override
+        public ParceledListSlice<SessionInfo> getAllSessions(String callingPackage) {
+            verifyCallingPackage(callingPackage);
+            List<SessionInfo> sessionInfos = new ArrayList<>();
+            int[] userIds = mUm.getEnabledProfileIds(getCallingUserId());
+            long token = Binder.clearCallingIdentity();
+            try {
+                for (int userId : userIds) {
+                    sessionInfos.addAll(getPackageInstallerService().getAllSessions(userId)
+                            .getList());
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            return new ParceledListSlice<>(sessionInfos);
+        }
+
+        private PackageInstallerService getPackageInstallerService() {
+            if (mPackageInstallerService == null) {
+                mPackageInstallerService = ((PackageInstallerService) ((PackageManagerService)
+                        ServiceManager.getService("package")).getPackageInstaller());
+            }
+            return mPackageInstallerService;
+        }
+
+        /**
          * Register a receiver to watch for package broadcasts
          */
         private void startWatchingPackageBroadcasts() {
@@ -869,6 +910,29 @@
         }
 
         @Override
+        public void startSessionDetailsActivityAsUser(IApplicationThread caller,
+                String callingPackage, SessionInfo sessionInfo, Rect sourceBounds,
+                Bundle opts, UserHandle userHandle) throws RemoteException {
+            int userId = userHandle.getIdentifier();
+            if (!canAccessProfile(userId, "Cannot start details activity")) {
+                return;
+            }
+
+            Intent i = new Intent(Intent.ACTION_VIEW)
+                    .setData(new Uri.Builder()
+                            .scheme("market")
+                            .authority("details")
+                            .appendQueryParameter("id", sessionInfo.appPackageName)
+                            .build())
+                    .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app")
+                            .authority(callingPackage).build());
+            i.setSourceBounds(sourceBounds);
+
+            mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, i, opts,
+                    userId);
+        }
+
+        @Override
         public void startActivityAsUser(IApplicationThread caller, String callingPackage,
                 ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 146a2f3..a3e0d8d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -59,7 +59,6 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SELinux;
-import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.system.ErrnoException;
@@ -107,6 +106,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Random;
+import java.util.function.IntPredicate;
 
 /** The service responsible for installing packages. */
 public class PackageInstallerService extends IPackageInstaller.Stub implements
@@ -804,7 +804,14 @@
     public void registerCallback(IPackageInstallerCallback callback, int userId) {
         mPermissionManager.enforceCrossUserPermission(
                 Binder.getCallingUid(), userId, true, false, "registerCallback");
-        mCallbacks.register(callback, userId);
+        registerCallback(callback, eventUserId -> userId == eventUserId);
+    }
+
+    /**
+     * Assume permissions already checked and caller's identity cleared
+     */
+    public void registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck) {
+        mCallbacks.register(callback, userCheck);
     }
 
     @Override
@@ -1026,8 +1033,8 @@
             super(looper);
         }
 
-        public void register(IPackageInstallerCallback callback, int userId) {
-            mCallbacks.register(callback, new UserHandle(userId));
+        public void register(IPackageInstallerCallback callback, IntPredicate userCheck) {
+            mCallbacks.register(callback, userCheck);
         }
 
         public void unregister(IPackageInstallerCallback callback) {
@@ -1040,9 +1047,8 @@
             final int n = mCallbacks.beginBroadcast();
             for (int i = 0; i < n; i++) {
                 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
-                final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
-                // TODO: dispatch notifications for slave profiles
-                if (userId == user.getIdentifier()) {
+                final IntPredicate userCheck = (IntPredicate) mCallbacks.getBroadcastCookie(i);
+                if (userCheck.test(userId)) {
                     try {
                         invokeCallback(callback, msg);
                     } catch (RemoteException ignored) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 494ec3f..de0849f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -473,6 +473,7 @@
         final SessionInfo info = new SessionInfo();
         synchronized (mLock) {
             info.sessionId = sessionId;
+            info.userId = userId;
             info.installerPackageName = mInstallerPackageName;
             info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
                     mResolvedBaseFile.getAbsolutePath() : null;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4f20590..d0f192d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1109,14 +1109,7 @@
 
     @Override
     public int getManagedProfileBadge(@UserIdInt int userId) {
-        int callingUserId = UserHandle.getCallingUserId();
-        if (callingUserId != userId && !hasManageUsersPermission()) {
-            if (!isSameProfileGroupNoChecks(callingUserId, userId)) {
-                throw new SecurityException(
-                        "You need MANAGE_USERS permission to: check if specified user a " +
-                        "managed profile outside your profile group");
-            }
-        }
+        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "getManagedProfileBadge");
         synchronized (mUsersLock) {
             UserInfo userInfo = getUserInfoLU(userId);
             return userInfo != null ? userInfo.profileBadge : 0;
@@ -1125,14 +1118,7 @@
 
     @Override
     public boolean isManagedProfile(int userId) {
-        int callingUserId = UserHandle.getCallingUserId();
-        if (callingUserId != userId && !hasManageUsersPermission()) {
-            if (!isSameProfileGroupNoChecks(callingUserId, userId)) {
-                throw new SecurityException(
-                        "You need MANAGE_USERS permission to: check if specified user a " +
-                        "managed profile outside your profile group");
-            }
-        }
+        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isManagedProfile");
         synchronized (mUsersLock) {
             UserInfo userInfo = getUserInfoLU(userId);
             return userInfo != null && userInfo.isManagedProfile();
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 0d888dc..988d75c 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -32,9 +32,67 @@
 // TODO(112037636): Always include once fsverity.h is upstreamed.
 #if __has_include(<linux/fsverity.h>)
 #include <linux/fsverity.h>
-const int kSha256Bytes = 32;
+#else
+
+// Before fs-verity is upstreamed, use the current snapshot for development.
+// https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/tree/include/uapi/linux/fsverity.h?h=fsverity
+
+#include <linux/limits.h>
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+struct fsverity_digest {
+    __u16 digest_algorithm;
+    __u16 digest_size; /* input/output */
+    __u8 digest[];
+};
+
+#define FS_IOC_ENABLE_VERITY	_IO('f', 133)
+#define FS_IOC_MEASURE_VERITY	_IOWR('f', 134, struct fsverity_digest)
+
+#define FS_VERITY_MAGIC		"FSVerity"
+
+#define FS_VERITY_ALG_SHA256	1
+
+struct fsverity_descriptor {
+    __u8 magic[8];		/* must be FS_VERITY_MAGIC */
+    __u8 major_version;	/* must be 1 */
+    __u8 minor_version;	/* must be 0 */
+    __u8 log_data_blocksize;/* log2(data-bytes-per-hash), e.g. 12 for 4KB */
+    __u8 log_tree_blocksize;/* log2(tree-bytes-per-hash), e.g. 12 for 4KB */
+    __le16 data_algorithm;	/* hash algorithm for data blocks */
+    __le16 tree_algorithm;	/* hash algorithm for tree blocks */
+    __le32 flags;		/* flags */
+    __le32 __reserved1;	/* must be 0 */
+    __le64 orig_file_size;	/* size of the original file data */
+    __le16 auth_ext_count;	/* number of authenticated extensions */
+    __u8 __reserved2[30];	/* must be 0 */
+};
+
+#define FS_VERITY_EXT_ROOT_HASH		1
+#define FS_VERITY_EXT_PKCS7_SIGNATURE	3
+
+struct fsverity_extension {
+    __le32 length;
+    __le16 type;		/* Type of this extension (see codes above) */
+    __le16 __reserved;	/* Reserved, must be 0 */
+};
+
+struct fsverity_digest_disk {
+    __le16 digest_algorithm;
+    __le16 digest_size;
+    __u8 digest[];
+};
+
+struct fsverity_footer {
+    __le32 desc_reverse_offset;	/* distance to fsverity_descriptor */
+    __u8 magic[8];			/* FS_VERITY_MAGIC */
+} __packed;
+
 #endif
 
+const int kSha256Bytes = 32;
+
 namespace android {
 
 namespace {
@@ -73,7 +131,6 @@
 };
 
 int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
-#if __has_include(<linux/fsverity.h>)
     const char* path = env->GetStringUTFChars(filePath, nullptr);
     ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
     if (rfd.get() < 0) {
@@ -83,14 +140,9 @@
       return errno;
     }
     return 0;
-#else
-    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
-    return ENOSYS;
-#endif
 }
 
 int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
-#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes);
     fsverity_digest* data = reinterpret_cast<fsverity_digest*>(raii->getRaw());
     data->digest_size = kSha256Bytes;  // the only input/output parameter
@@ -104,14 +156,9 @@
       return errno;
     }
     return 0;
-#else
-    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
-    return ENOSYS;
-#endif
 }
 
 jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteArray digest) {
-#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest_disk) + kSha256Bytes);
     fsverity_digest_disk* data = reinterpret_cast<fsverity_digest_disk*>(raii->getRaw());
 
@@ -126,15 +173,10 @@
     memcpy(data->digest, src, kSha256Bytes);
 
     return raii->release();
-#else
-    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
-    return 0;
-#endif
 }
 
 
 jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) {
-#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor));
     fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw());
 
@@ -150,15 +192,10 @@
     desc->auth_ext_count = 1;
 
     return raii->release();
-#else
-    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
-    return 0;
-#endif
 }
 
 jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId,
         jint extensionDataSize) {
-#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension));
     fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw());
 
@@ -166,15 +203,10 @@
     ext->type = extensionId;
 
     return raii->release();
-#else
-    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
-    return 0;
-#endif
 }
 
 jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */,
         jint offsetToDescriptorHead) {
-#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer));
     fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw());
 
@@ -182,10 +214,6 @@
     memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic));
 
     return raii->release();
-#else
-    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
-    return 0;
-#endif
 }
 
 const JNINativeMethod sMethods[] = {
diff --git a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
index 1a231cf..2f8e545 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
@@ -18,6 +18,7 @@
 
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_STATSD_SAMPLE_RATE;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2;
 import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3;
@@ -61,6 +62,9 @@
 @RunWith(AndroidJUnit4.class)
 public final class AppCompactorTest {
 
+    private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
+            "device_config delete activity_manager";
+
     @Mock private AppOpsService mAppOpsService;
     private AppCompactor mCompactorUnderTest;
     private HandlerThread mHandlerThread;
@@ -70,19 +74,21 @@
     private static void clearDeviceConfig() throws IOException  {
         UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
         uiDevice.executeShellCommand(
-                "device_config delete activity_manager " + KEY_USE_COMPACTION);
+                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_USE_COMPACTION);
         uiDevice.executeShellCommand(
-                "device_config delete activity_manager " + KEY_COMPACT_ACTION_1);
+                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_1);
         uiDevice.executeShellCommand(
-                "device_config delete activity_manager " + KEY_COMPACT_ACTION_2);
+                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_2);
         uiDevice.executeShellCommand(
-                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_1);
+                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_1);
         uiDevice.executeShellCommand(
-                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_2);
+                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_2);
         uiDevice.executeShellCommand(
-                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_3);
+                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_3);
         uiDevice.executeShellCommand(
-                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_4);
+                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_4);
+        uiDevice.executeShellCommand(
+                CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_STATSD_SAMPLE_RATE);
     }
 
     @Before
@@ -128,6 +134,8 @@
                 is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
         assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
                 is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
+        assertThat(mCompactorUnderTest.mStatsdSampleRate,
+                is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE));
     }
 
     @Test
@@ -155,6 +163,9 @@
         DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                 KEY_COMPACT_THROTTLE_4,
                 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_STATSD_SAMPLE_RATE,
+                Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
 
         // Then calling init will read and set that flag.
         mCompactorUnderTest.init();
@@ -173,6 +184,8 @@
                 is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1));
         assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
                 is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1));
+        assertThat(mCompactorUnderTest.mStatsdSampleRate,
+                is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f));
     }
 
     @Test
@@ -365,6 +378,63 @@
                 is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
     }
 
+    @Test
+    public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException {
+        mCompactorUnderTest.init();
+
+        // When we override mStatsdSampleRate with a reasonable values ...
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_STATSD_SAMPLE_RATE,
+                Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        // Then that override is reflected in the compactor.
+        assertThat(mCompactorUnderTest.mStatsdSampleRate,
+                is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f));
+    }
+
+    @Test
+    public void statsdSanokeRate_listensToDeviceConfigChangesBadValues()
+            throws InterruptedException {
+        mCompactorUnderTest.init();
+
+        // When we override mStatsdSampleRate with a reasonable values ...
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        // Then that override is reflected in the compactor.
+        assertThat(mCompactorUnderTest.mStatsdSampleRate,
+                is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE));
+    }
+
+    @Test
+    public void statsdSanokeRate_listensToDeviceConfigChangesOutOfRangeValues()
+            throws InterruptedException {
+        mCompactorUnderTest.init();
+
+        // When we override mStatsdSampleRate with an value outside of [0..1]...
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_STATSD_SAMPLE_RATE,
+                Float.toString(-1.0f), false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        // Then the values is capped in the range.
+        assertThat(mCompactorUnderTest.mStatsdSampleRate, is(0.0f));
+
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_STATSD_SAMPLE_RATE,
+                Float.toString(1.01f), false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        // Then the values is capped in the range.
+        assertThat(mCompactorUnderTest.mStatsdSampleRate, is(1.0f));
+    }
+
     private class TestInjector extends Injector {
         @Override
         public AppOpsService getAppOpsService(File file, Handler handler) {
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
index 9a30b35..22fc159 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -50,8 +50,8 @@
     public static final String TAG = "IorapForwardingService";
     /** $> adb shell 'setprop log.tag.IorapdForwardingService VERBOSE' */
     public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    /** $> adb shell 'setprop iorapd.enable true' */
-    private static boolean IS_ENABLED = SystemProperties.getBoolean("iorapd.enable", true);
+    /** $> adb shell 'setprop ro.iorapd.enable true' */
+    private static boolean IS_ENABLED = SystemProperties.getBoolean("ro.iorapd.enable", true);
     /** $> adb shell 'setprop iorapd.forwarding_service.wtf_crash true' */
     private static boolean WTF_CRASH = SystemProperties.getBoolean(
             "iorapd.forwarding_service.wtf_crash", false);
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index 4bca404..6c45cc4 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
@@ -112,13 +113,13 @@
                     mSlotId, 0, null).sendToTarget();
         }
 
-        private void registerForStateChanged(INetworkServiceCallback callback) {
+        private void registerForStateChanged(@NonNull INetworkServiceCallback callback) {
             synchronized (mNetworkRegistrationStateChangedCallbacks) {
                 mNetworkRegistrationStateChangedCallbacks.add(callback);
             }
         }
 
-        private void unregisterForStateChanged(INetworkServiceCallback callback) {
+        private void unregisterForStateChanged(@NonNull INetworkServiceCallback callback) {
             synchronized (mNetworkRegistrationStateChangedCallbacks) {
                 mNetworkRegistrationStateChangedCallbacks.remove(callback);
             }
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 74d1e83..79572b9 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -157,7 +157,10 @@
                                   @Nullable LinkProperties linkProperties,
                                   @Nullable DataServiceCallback callback) {
             // The default implementation is to return unsupported.
-            callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
+            if (callback != null) {
+                callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED,
+                        null);
+            }
         }
 
         /**
@@ -176,7 +179,9 @@
         public void deactivateDataCall(int cid, @DeactivateDataReason int reason,
                                        @Nullable DataServiceCallback callback) {
             // The default implementation is to return unsupported.
-            callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+            if (callback != null) {
+                callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+            }
         }
 
         /**
@@ -190,7 +195,10 @@
         public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
                                         @Nullable DataServiceCallback callback) {
             // The default implementation is to return unsupported.
-            callback.onSetInitialAttachApnComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+            if (callback != null) {
+                callback.onSetInitialAttachApnComplete(
+                        DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+            }
         }
 
         /**
@@ -206,7 +214,9 @@
         public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
                                    @Nullable DataServiceCallback callback) {
             // The default implementation is to return unsupported.
-            callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+            if (callback != null) {
+                callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+            }
         }
 
         /**